diff --git a/instant-xml-macros/src/ser.rs b/instant-xml-macros/src/ser.rs index e17e703..40fff98 100644 --- a/instant-xml-macros/src/ser.rs +++ b/instant-xml-macros/src/ser.rs @@ -311,8 +311,13 @@ impl StructOutput { .collect::, _>>() .map_err(|err| err.to_compile_error())?; + let mut attrs_only = true; let mut direct = None; for (field, field_meta) in &fields { + if !field_meta.attribute { + attrs_only = false; + } + if direct.is_some() { return Err( syn::Error::new(field.span(), "direct field must be the last") @@ -326,14 +331,15 @@ impl StructOutput { } if !inline { - self.body.extend(match direct { - Some(field) => quote!( + self.body.extend(match (attrs_only, direct) { + (true, _) => quote!(serializer.end_empty()?;), + (false, Some(field)) => quote!( match self.#field.present() { true => serializer.end_start()?, false => serializer.end_empty()?, } ), - None => quote!(serializer.end_start()?;), + (false, None) => quote!(serializer.end_start()?;), }) } @@ -351,7 +357,7 @@ impl StructOutput { } } - if !inline { + if !inline && !attrs_only { let tag = meta.tag(); self.body.extend(match direct { Some(field) => quote!( diff --git a/instant-xml/tests/attr-no-ns.rs b/instant-xml/tests/attributes.rs similarity index 57% rename from instant-xml/tests/attr-no-ns.rs rename to instant-xml/tests/attributes.rs index 759318c..c3f4f0b 100644 --- a/instant-xml/tests/attr-no-ns.rs +++ b/instant-xml/tests/attributes.rs @@ -11,13 +11,13 @@ struct Basic { #[test] fn basic() { assert_eq!( - from_str::(""), + from_str::(""), Ok(Basic { flag: true }) ); assert_eq!( to_string(&Basic { flag: true }).unwrap(), - "" + "" ); } @@ -31,3 +31,18 @@ fn empty() { Ok(Empty) ); } + +#[derive(ToXml)] +#[xml(ns(bar = "BAR"))] +struct NoPrefixAttrNs { + #[xml(attribute, ns(bar))] + flag: bool, +} + +#[test] +fn no_prefix_attr_ns() { + assert_eq!( + to_string(&NoPrefixAttrNs { flag: true }).unwrap(), + "" + ); +} diff --git a/instant-xml/tests/de-direct.rs b/instant-xml/tests/de-direct.rs deleted file mode 100644 index e3ec9f0..0000000 --- a/instant-xml/tests/de-direct.rs +++ /dev/null @@ -1,104 +0,0 @@ -use std::borrow::Cow; - -use similar_asserts::assert_eq; - -use instant_xml::{from_str, Error, FromXml}; - -#[derive(Debug, Eq, PartialEq, FromXml)] -#[xml(ns("URI"))] -struct StructDirectNamespace { - #[xml(ns("BAZ"))] - flag: bool, -} - -#[test] -fn direct_namespaces() { - // Correct direct namespace - assert_eq!( - from_str( - "true" - ), - Ok(StructDirectNamespace { flag: true }) - ); - - // Wrong direct namespace - assert_eq!( - from_str( - "true" - ), - Err::(Error::MissingValue("StructDirectNamespace::flag")) - ); - - // Wrong direct namespace - missing namespace - assert_eq!( - from_str("true"), - Err::(Error::MissingValue("StructDirectNamespace::flag")) - ); -} - -#[derive(Debug, Eq, PartialEq, FromXml)] -struct DirectString { - s: String, -} - -#[test] -fn direct_string() { - assert_eq!( - from_str("hello"), - Ok(DirectString { - s: "hello".to_string() - }) - ); -} - -#[derive(Debug, Eq, PartialEq, FromXml)] -struct DirectStr<'a> { - s: Cow<'a, str>, -} - -#[test] -fn direct_empty_str() { - assert_eq!( - from_str(""), - Ok(DirectStr { s: "".into() }) - ); -} - -#[test] -fn direct_missing_string() { - assert_eq!( - from_str(""), - Err::(Error::MissingValue("DirectString::s")) - ); -} - -#[derive(Debug, PartialEq, FromXml)] -struct ArtUri { - #[xml(direct)] - uri: String, -} - -#[derive(Debug, PartialEq, FromXml)] -struct Container { - art: Option, -} - -#[test] -fn container_empty_string() { - assert_eq!( - from_str(""), - Ok(Container { - art: Some(ArtUri { - uri: "".to_string() - }) - }) - ); - assert_eq!( - from_str(""), - Ok(Container { - art: Some(ArtUri { - uri: "".to_string() - }) - }) - ); -} diff --git a/instant-xml/tests/direct-no-value.rs b/instant-xml/tests/direct-no-value.rs deleted file mode 100644 index 3339d7f..0000000 --- a/instant-xml/tests/direct-no-value.rs +++ /dev/null @@ -1,21 +0,0 @@ -use instant_xml::{from_str, to_string, FromXml, ToXml}; - -#[derive(ToXml, FromXml, Debug, PartialEq, Eq)] -struct Foo { - #[xml(attribute)] - attribute: Option, - #[xml(direct)] - direct: Option, -} - -#[test] -fn serde_direct_no_value_test() { - let v = Foo { - attribute: Some("Attribute text".to_string()), - direct: None, - }; - let xml = r#""#; - - assert_eq!(xml, to_string(&v).unwrap()); //this fails because the serializer still writes "" - assert_eq!(from_str::(xml).unwrap(), v); //this fails because the serializer still writes Some("") to direct -} diff --git a/instant-xml/tests/direct.rs b/instant-xml/tests/direct.rs index 17e1f28..445cb9d 100644 --- a/instant-xml/tests/direct.rs +++ b/instant-xml/tests/direct.rs @@ -1,6 +1,8 @@ +use std::borrow::Cow; + use similar_asserts::assert_eq; -use instant_xml::{from_str, to_string, FromXml, ToXml}; +use instant_xml::{from_str, to_string, Error, FromXml, ToXml}; #[derive(Clone, Debug, Eq, FromXml, PartialEq, ToXml)] struct Foo { @@ -30,3 +32,122 @@ fn direct() { let xml = "cbdté"; assert_eq!(from_str::(xml), Ok(v)); } + +#[derive(Debug, Eq, PartialEq, FromXml)] +#[xml(ns("URI"))] +struct StructDirectNamespace { + #[xml(ns("BAZ"))] + flag: bool, +} + +#[test] +fn direct_namespaces() { + // Correct direct namespace + assert_eq!( + from_str( + "true" + ), + Ok(StructDirectNamespace { flag: true }) + ); + + // Wrong direct namespace + assert_eq!( + from_str( + "true" + ), + Err::(Error::MissingValue("StructDirectNamespace::flag")) + ); + + // Wrong direct namespace - missing namespace + assert_eq!( + from_str("true"), + Err::(Error::MissingValue("StructDirectNamespace::flag")) + ); +} + +#[derive(Debug, Eq, PartialEq, FromXml)] +struct DirectString { + s: String, +} + +#[test] +fn direct_string() { + assert_eq!( + from_str("hello"), + Ok(DirectString { + s: "hello".to_string() + }) + ); +} + +#[derive(Debug, Eq, PartialEq, FromXml)] +struct DirectStr<'a> { + s: Cow<'a, str>, +} + +#[test] +fn direct_empty_str() { + assert_eq!( + from_str(""), + Ok(DirectStr { s: "".into() }) + ); +} + +#[test] +fn direct_missing_string() { + assert_eq!( + from_str(""), + Err::(Error::MissingValue("DirectString::s")) + ); +} + +#[derive(Debug, PartialEq, FromXml)] +struct ArtUri { + #[xml(direct)] + uri: String, +} + +#[derive(Debug, PartialEq, FromXml)] +struct Container { + art: Option, +} + +#[test] +fn container_empty_string() { + assert_eq!( + from_str(""), + Ok(Container { + art: Some(ArtUri { + uri: "".to_string() + }) + }) + ); + assert_eq!( + from_str(""), + Ok(Container { + art: Some(ArtUri { + uri: "".to_string() + }) + }) + ); +} + +#[derive(ToXml, FromXml, Debug, PartialEq, Eq)] +struct Options { + #[xml(attribute)] + attribute: Option, + #[xml(direct)] + direct: Option, +} + +#[test] +fn direct_options() { + let v = Options { + attribute: Some("Attribute text".to_string()), + direct: None, + }; + let xml = r#""#; + + assert_eq!(xml, to_string(&v).unwrap()); + assert_eq!(from_str::(xml).unwrap(), v); +} diff --git a/instant-xml/tests/option.rs b/instant-xml/tests/option.rs index 5a597a2..e812ccd 100644 --- a/instant-xml/tests/option.rs +++ b/instant-xml/tests/option.rs @@ -31,13 +31,13 @@ fn option_borrow() { let v = Bar { maybe: Some("a".into()), }; - let xml = r#""#; + let xml = r#""#; assert_eq!(xml, to_string(&v).unwrap()); assert_eq!(v, from_str(xml).unwrap()); let v = Bar { maybe: None }; - let xml = r#""#; + let xml = r#""#; assert_eq!(xml, to_string(&v).unwrap()); assert_eq!(v, from_str(xml).unwrap()); diff --git a/instant-xml/tests/rename.rs b/instant-xml/tests/rename.rs index dd38774..65411be 100644 --- a/instant-xml/tests/rename.rs +++ b/instant-xml/tests/rename.rs @@ -18,7 +18,7 @@ fn renamed() { assert_eq!( to_string(&Renamed { flag: true }).unwrap(), - "" + "" ); } diff --git a/instant-xml/tests/ser-attr-ns.rs b/instant-xml/tests/ser-attr-ns.rs deleted file mode 100644 index 603bb3f..0000000 --- a/instant-xml/tests/ser-attr-ns.rs +++ /dev/null @@ -1,18 +0,0 @@ -use similar_asserts::assert_eq; - -use instant_xml::{to_string, ToXml}; - -#[derive(ToXml)] -#[xml(ns(bar = "BAR"))] -struct NoPrefixAttrNs { - #[xml(attribute, ns(bar))] - flag: bool, -} - -#[test] -fn no_prefix_attr_ns() { - assert_eq!( - to_string(&NoPrefixAttrNs { flag: true }).unwrap(), - "" - ); -}