diff --git a/xsd-parser/src/pipeline/renderer/steps/quick_xml/deserialize.rs b/xsd-parser/src/pipeline/renderer/steps/quick_xml/deserialize.rs index 1ceafaf4..f0b65fd0 100644 --- a/xsd-parser/src/pipeline/renderer/steps/quick_xml/deserialize.rs +++ b/xsd-parser/src/pipeline/renderer/steps/quick_xml/deserialize.rs @@ -3137,9 +3137,18 @@ impl ComplexDataElement<'_> { Occurs::Optional => quote!(Ok(super::#type_ident::#variant_ident(None))), Occurs::DynamicList => { let min = self.meta().min_occurs; - - quote! { - Ok(super::#type_ident::#variant_ident(helper.finish_vec_default(#min, Vec::new())?)) + // finish_vec_default() requires the deserializer to implement Default. + // BUT, if min is 0, then it doesn't need to have a default value -- the + // underlying type doesn't need to be defaultable if a Vec of it is allowed + // to be empty + if min == 0 { + quote! { + Ok(super::#type_ident::#variant_ident(Vec::new())) + } + } else { + quote! { + Ok(super::#type_ident::#variant_ident(helper.finish_vec_default(#min, Vec::new())?)) + } } } Occurs::StaticList(sz) => { @@ -4276,6 +4285,9 @@ impl DefaultableCache { } fn is_defaultable_element(&mut self, types: &MetaTypes, el: &ElementMeta) -> bool { + if el.min_occurs == 0 { + return true; + } if let ElementMetaVariant::Type { type_, mode: ElementMode::Group, @@ -4344,16 +4356,8 @@ impl DefaultableCache { defaultable } Some(MetaTypeVariant::Choice(x)) => { - let defaultable = x.elements.len() == 1 - && x.elements[0].min_occurs >= 1 - && matches!( - &x.elements[0].variant, - ElementMetaVariant::Type { - mode: ElementMode::Group, - .. - } - ); - + let defaultable = + x.elements.len() == 1 && self.is_defaultable_element(types, &x.elements[0]); if defaultable { Defaultable::Complete } else { diff --git a/xsd-parser/tests/feature/choice_single_option_defaults/example/defaultable.xml b/xsd-parser/tests/feature/choice_single_option_defaults/example/defaultable.xml new file mode 100644 index 00000000..8360668f --- /dev/null +++ b/xsd-parser/tests/feature/choice_single_option_defaults/example/defaultable.xml @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/xsd-parser/tests/feature/choice_single_option_defaults/example/not_defaultable.xml b/xsd-parser/tests/feature/choice_single_option_defaults/example/not_defaultable.xml new file mode 100644 index 00000000..187c924d --- /dev/null +++ b/xsd-parser/tests/feature/choice_single_option_defaults/example/not_defaultable.xml @@ -0,0 +1,9 @@ + + + test 1 + test 2 + diff --git a/xsd-parser/tests/feature/choice_single_option_defaults/expected/default.rs b/xsd-parser/tests/feature/choice_single_option_defaults/expected/default.rs new file mode 100644 index 00000000..8327bab2 --- /dev/null +++ b/xsd-parser/tests/feature/choice_single_option_defaults/expected/default.rs @@ -0,0 +1,26 @@ +pub type Foo = FooType; +#[derive(Debug)] +pub struct FooType { + pub content: FooTypeContent, +} +#[derive(Debug)] +pub enum FooTypeContent { + Content2(Vec), +} +#[derive(Debug)] +pub struct FooContent2Type { + pub info: String, +} +pub type Bar = BarType; +#[derive(Debug)] +pub struct BarType { + pub content: BarTypeContent, +} +#[derive(Debug)] +pub enum BarTypeContent { + Content4(Vec), +} +#[derive(Debug)] +pub struct BarContent4Type { + pub info: String, +} diff --git a/xsd-parser/tests/feature/choice_single_option_defaults/expected/quick_xml.rs b/xsd-parser/tests/feature/choice_single_option_defaults/expected/quick_xml.rs new file mode 100644 index 00000000..a4a757fc --- /dev/null +++ b/xsd-parser/tests/feature/choice_single_option_defaults/expected/quick_xml.rs @@ -0,0 +1,1121 @@ +use xsd_parser_types::{misc::Namespace, quick_xml::WithDeserializer}; +pub const NS_XS: Namespace = Namespace::new_const(b"http://www.w3.org/2001/XMLSchema"); +pub const NS_XML: Namespace = Namespace::new_const(b"http://www.w3.org/XML/1998/namespace"); +pub const NS_XSI: Namespace = Namespace::new_const(b"http://www.w3.org/2001/XMLSchema-instance"); +pub const NS_TNS: Namespace = Namespace::new_const(b"http://example.com"); +pub type Foo = FooType; +#[derive(Debug)] +pub struct FooType { + pub content: FooTypeContent, +} +#[derive(Debug)] +pub enum FooTypeContent { + Content2(Vec), +} +impl WithDeserializer for FooType { + type Deserializer = quick_xml_deserialize::FooTypeDeserializer; +} +impl WithDeserializer for FooTypeContent { + type Deserializer = quick_xml_deserialize::FooTypeContentDeserializer; +} +#[derive(Debug)] +pub struct FooContent2Type { + pub info: String, +} +impl WithDeserializer for FooContent2Type { + type Deserializer = quick_xml_deserialize::FooContent2TypeDeserializer; +} +pub type Bar = BarType; +#[derive(Debug)] +pub struct BarType { + pub content: BarTypeContent, +} +#[derive(Debug)] +pub enum BarTypeContent { + Content4(Vec), +} +impl WithDeserializer for BarType { + type Deserializer = quick_xml_deserialize::BarTypeDeserializer; +} +impl WithDeserializer for BarTypeContent { + type Deserializer = quick_xml_deserialize::BarTypeContentDeserializer; +} +#[derive(Debug)] +pub struct BarContent4Type { + pub info: String, +} +impl WithDeserializer for BarContent4Type { + type Deserializer = quick_xml_deserialize::BarContent4TypeDeserializer; +} +pub mod quick_xml_deserialize { + use core::mem::replace; + use xsd_parser_types::quick_xml::{ + BytesStart, DeserializeHelper, Deserializer, DeserializerArtifact, DeserializerEvent, + DeserializerOutput, DeserializerResult, ElementHandlerOutput, Error, ErrorKind, Event, + RawByteStr, WithDeserializer, + }; + #[derive(Debug)] + pub struct FooTypeDeserializer { + content: Option, + state__: Box, + } + #[derive(Debug)] + enum FooTypeDeserializerState { + Init__, + Next__, + Content__(::Deserializer), + Unknown__, + } + impl FooTypeDeserializer { + fn from_bytes_start( + helper: &mut DeserializeHelper, + bytes_start: &BytesStart<'_>, + ) -> Result { + for attrib in helper.filter_xmlns_attributes(bytes_start) { + let attrib = attrib?; + helper.raise_unexpected_attrib_checked(&attrib)?; + } + Ok(Self { + content: None, + state__: Box::new(FooTypeDeserializerState::Init__), + }) + } + fn finish_state( + &mut self, + helper: &mut DeserializeHelper, + state: FooTypeDeserializerState, + ) -> Result<(), Error> { + if let FooTypeDeserializerState::Content__(deserializer) = state { + self.store_content(deserializer.finish(helper)?)?; + } + Ok(()) + } + fn store_content(&mut self, value: super::FooTypeContent) -> Result<(), Error> { + if self.content.is_some() { + Err(ErrorKind::DuplicateContent)?; + } + self.content = Some(value); + Ok(()) + } + fn handle_content<'de>( + &mut self, + helper: &mut DeserializeHelper, + output: DeserializerOutput<'de, super::FooTypeContent>, + fallback: &mut Option, + ) -> Result, Error> { + use FooTypeDeserializerState as S; + let DeserializerOutput { + artifact, + event, + allow_any, + } = output; + if artifact.is_none() { + *self.state__ = fallback.take().unwrap_or(S::Next__); + return Ok(ElementHandlerOutput::from_event_end(event, allow_any)); + } + if let Some(fallback) = fallback.take() { + self.finish_state(helper, fallback)?; + } + match artifact { + DeserializerArtifact::None => unreachable!(), + DeserializerArtifact::Data(data) => { + self.store_content(data)?; + *self.state__ = S::Next__; + Ok(ElementHandlerOutput::from_event(event, allow_any)) + } + DeserializerArtifact::Deserializer(deserializer) => { + *self.state__ = S::Content__(deserializer); + Ok(ElementHandlerOutput::from_event_end(event, allow_any)) + } + } + } + } + impl<'de> Deserializer<'de, super::FooType> for FooTypeDeserializer { + fn init( + helper: &mut DeserializeHelper, + event: Event<'de>, + ) -> DeserializerResult<'de, super::FooType> { + helper.init_deserializer_from_start_event(event, Self::from_bytes_start) + } + fn next( + mut self, + helper: &mut DeserializeHelper, + event: Event<'de>, + ) -> DeserializerResult<'de, super::FooType> { + use FooTypeDeserializerState as S; + let mut event = event; + let mut fallback = None; + let (event, allow_any) = loop { + let state = replace(&mut *self.state__, S::Unknown__); + event = match (state, event) { + (S::Unknown__, _) => unreachable!(), + (S::Content__(deserializer), event) => { + let output = deserializer.next(helper, event)?; + match self.handle_content(helper, output, &mut fallback)? { + ElementHandlerOutput::Break { event, allow_any } => { + break (event, allow_any) + } + ElementHandlerOutput::Continue { event, .. } => event, + } + } + (_, Event::End(_)) => { + return Ok(DeserializerOutput { + artifact: DeserializerArtifact::Data(self.finish(helper)?), + event: DeserializerEvent::None, + allow_any: false, + }); + } + (state @ (S::Init__ | S::Next__), event) => { + fallback.get_or_insert(state); + let output = + ::init(helper, event)?; + match self.handle_content(helper, output, &mut fallback)? { + ElementHandlerOutput::Break { event, allow_any } => { + break (event, allow_any) + } + ElementHandlerOutput::Continue { event, .. } => event, + } + } + } + }; + if let Some(fallback) = fallback { + *self.state__ = fallback; + } + let artifact = DeserializerArtifact::Deserializer(self); + Ok(DeserializerOutput { + artifact, + event, + allow_any, + }) + } + fn finish(mut self, helper: &mut DeserializeHelper) -> Result { + let state = replace(&mut *self.state__, FooTypeDeserializerState::Unknown__); + self.finish_state(helper, state)?; + Ok(super::FooType { + content: helper.finish_content(self.content)?, + }) + } + } + #[derive(Debug)] + pub struct FooTypeContentDeserializer { + state__: Box, + } + #[derive(Debug)] + pub enum FooTypeContentDeserializerState { + Init__, + Content2( + Vec, + Option<::Deserializer>, + Option<::Deserializer>, + ), + Done__(super::FooTypeContent), + Unknown__, + } + impl FooTypeContentDeserializer { + fn find_suitable<'de>( + &mut self, + helper: &mut DeserializeHelper, + event: Event<'de>, + ) -> Result, Error> { + let mut event = event; + let mut allow_any_element = false; + if let Event::Start(_) | Event::Empty(_) = &event { + event = { + let output = ::init(helper, event)?; + match self.handle_content_2(helper, Default::default(), None, output)? { + ElementHandlerOutput::Continue { event, allow_any } => { + allow_any_element = allow_any_element || allow_any; + event + } + output => { + return Ok(output); + } + } + }; + } + *self.state__ = FooTypeContentDeserializerState::Init__; + Ok(ElementHandlerOutput::return_to_parent( + event, + allow_any_element, + )) + } + fn finish_state( + helper: &mut DeserializeHelper, + state: FooTypeContentDeserializerState, + ) -> Result { + use FooTypeContentDeserializerState as S; + match state { + S::Init__ => Err(ErrorKind::MissingContent.into()), + S::Content2(mut values, None, deserializer) => { + if let Some(deserializer) = deserializer { + let value = deserializer.finish(helper)?; + Self::store_content_2(&mut values, value)?; + } + Ok(super::FooTypeContent::Content2( + helper.finish_vec(1usize, None, values)?, + )) + } + S::Done__(data) => Ok(data), + _ => unreachable!(), + } + } + fn store_content_2( + values: &mut Vec, + value: super::FooContent2Type, + ) -> Result<(), Error> { + values.push(value); + Ok(()) + } + fn handle_content_2<'de>( + &mut self, + helper: &mut DeserializeHelper, + mut values: Vec, + fallback: Option<::Deserializer>, + output: DeserializerOutput<'de, super::FooContent2Type>, + ) -> Result, Error> { + use FooTypeContentDeserializerState as S; + let DeserializerOutput { + artifact, + event, + allow_any, + } = output; + if artifact.is_none() { + if fallback.is_none() && values.is_empty() { + *self.state__ = S::Init__; + return Ok(ElementHandlerOutput::from_event(event, allow_any)); + } else if values.len() + usize::from(fallback.is_some()) < 1usize { + *self.state__ = S::Content2(values, None, fallback); + return Ok(ElementHandlerOutput::return_to_root(event, allow_any)); + } else { + *self.state__ = S::Content2(values, None, fallback); + return Ok(ElementHandlerOutput::break_(event, allow_any)); + } + } + if let Some(deserializer) = fallback { + let data = deserializer.finish(helper)?; + Self::store_content_2(&mut values, data)?; + } + match artifact { + DeserializerArtifact::None => unreachable!(), + DeserializerArtifact::Data(data) => { + Self::store_content_2(&mut values, data)?; + *self.state__ = S::Content2(values, None, None); + Ok(ElementHandlerOutput::from_event(event, allow_any)) + } + DeserializerArtifact::Deserializer(deserializer) => { + let ret = ElementHandlerOutput::from_event(event, allow_any); + if ret.is_continue_start_or_empty() { + *self.state__ = S::Content2(values, Some(deserializer), None); + } else { + *self.state__ = S::Content2(values, None, Some(deserializer)); + } + Ok(ret) + } + } + } + } + impl<'de> Deserializer<'de, super::FooTypeContent> for FooTypeContentDeserializer { + fn init( + helper: &mut DeserializeHelper, + event: Event<'de>, + ) -> DeserializerResult<'de, super::FooTypeContent> { + let deserializer = Self { + state__: Box::new(FooTypeContentDeserializerState::Init__), + }; + let mut output = deserializer.next(helper, event)?; + output.artifact = match output.artifact { + DeserializerArtifact::Deserializer(x) + if matches!(&*x.state__, FooTypeContentDeserializerState::Init__) => + { + DeserializerArtifact::None + } + artifact => artifact, + }; + Ok(output) + } + fn next( + mut self, + helper: &mut DeserializeHelper, + event: Event<'de>, + ) -> DeserializerResult<'de, super::FooTypeContent> { + use FooTypeContentDeserializerState as S; + let mut event = event; + let (event, allow_any) = loop { + let state = replace(&mut *self.state__, S::Unknown__); + event = match (state, event) { + (S::Unknown__, _) => unreachable!(), + (S::Content2(values, fallback, Some(deserializer)), event) => { + let output = deserializer.next(helper, event)?; + match self.handle_content_2(helper, values, fallback, output)? { + ElementHandlerOutput::Break { event, allow_any } => { + break (event, allow_any) + } + ElementHandlerOutput::Continue { event, .. } => event, + } + } + (state, event @ Event::End(_)) => { + return Ok(DeserializerOutput { + artifact: DeserializerArtifact::Data(Self::finish_state( + helper, state, + )?), + event: DeserializerEvent::Continue(event), + allow_any: false, + }); + } + (S::Init__, event) => match self.find_suitable(helper, event)? { + ElementHandlerOutput::Break { event, allow_any } => { + break (event, allow_any) + } + ElementHandlerOutput::Continue { event, .. } => event, + }, + ( + S::Content2(values, fallback, None), + event @ (Event::Start(_) | Event::Empty(_)), + ) => { + let output = + ::init(helper, event)?; + match self.handle_content_2(helper, values, fallback, output)? { + ElementHandlerOutput::Break { event, allow_any } => { + break (event, allow_any) + } + ElementHandlerOutput::Continue { event, .. } => event, + } + } + (state @ S::Done__(_), event) => { + *self.state__ = state; + break (DeserializerEvent::Continue(event), false); + } + (state, event) => { + *self.state__ = state; + break (DeserializerEvent::Continue(event), false); + } + } + }; + let artifact = if matches!(&*self.state__, S::Done__(_)) { + DeserializerArtifact::Data(self.finish(helper)?) + } else { + DeserializerArtifact::Deserializer(self) + }; + Ok(DeserializerOutput { + artifact, + event, + allow_any, + }) + } + fn finish(self, helper: &mut DeserializeHelper) -> Result { + Self::finish_state(helper, *self.state__) + } + } + #[derive(Debug)] + pub struct FooContent2TypeDeserializer { + info: Option, + state__: Box, + } + #[derive(Debug)] + enum FooContent2TypeDeserializerState { + Init__, + Info(Option<::Deserializer>), + Done__, + Unknown__, + } + impl FooContent2TypeDeserializer { + fn finish_state( + &mut self, + helper: &mut DeserializeHelper, + state: FooContent2TypeDeserializerState, + ) -> Result<(), Error> { + use FooContent2TypeDeserializerState as S; + match state { + S::Info(Some(deserializer)) => self.store_info(deserializer.finish(helper)?)?, + _ => (), + } + Ok(()) + } + fn store_info(&mut self, value: String) -> Result<(), Error> { + if self.info.is_some() { + Err(ErrorKind::DuplicateElement(RawByteStr::from_slice(b"info")))?; + } + self.info = Some(value); + Ok(()) + } + fn handle_info<'de>( + &mut self, + helper: &mut DeserializeHelper, + output: DeserializerOutput<'de, String>, + fallback: &mut Option, + ) -> Result, Error> { + use FooContent2TypeDeserializerState as S; + let DeserializerOutput { + artifact, + event, + allow_any, + } = output; + if artifact.is_none() { + fallback.get_or_insert(S::Info(None)); + if matches!(&fallback, Some(S::Init__)) { + return Ok(ElementHandlerOutput::break_(event, allow_any)); + } else { + return Ok(ElementHandlerOutput::return_to_root(event, allow_any)); + } + } + if let Some(fallback) = fallback.take() { + self.finish_state(helper, fallback)?; + } + match artifact { + DeserializerArtifact::None => unreachable!(), + DeserializerArtifact::Data(data) => { + self.store_info(data)?; + *self.state__ = S::Done__; + Ok(ElementHandlerOutput::from_event(event, allow_any)) + } + DeserializerArtifact::Deserializer(deserializer) => { + fallback.get_or_insert(S::Info(Some(deserializer))); + *self.state__ = S::Done__; + Ok(ElementHandlerOutput::from_event(event, allow_any)) + } + } + } + } + impl<'de> Deserializer<'de, super::FooContent2Type> for FooContent2TypeDeserializer { + fn init( + helper: &mut DeserializeHelper, + event: Event<'de>, + ) -> DeserializerResult<'de, super::FooContent2Type> { + let deserializer = Self { + info: None, + state__: Box::new(FooContent2TypeDeserializerState::Init__), + }; + let mut output = deserializer.next(helper, event)?; + output.artifact = match output.artifact { + DeserializerArtifact::Deserializer(x) + if matches!(&*x.state__, FooContent2TypeDeserializerState::Init__) => + { + DeserializerArtifact::None + } + artifact => artifact, + }; + Ok(output) + } + fn next( + mut self, + helper: &mut DeserializeHelper, + event: Event<'de>, + ) -> DeserializerResult<'de, super::FooContent2Type> { + use FooContent2TypeDeserializerState as S; + let mut event = event; + let mut fallback = None; + let mut allow_any_element = false; + let (event, allow_any) = loop { + let state = replace(&mut *self.state__, S::Unknown__); + event = match (state, event) { + (S::Unknown__, _) => unreachable!(), + (S::Info(Some(deserializer)), event) => { + let output = deserializer.next(helper, event)?; + match self.handle_info(helper, output, &mut fallback)? { + ElementHandlerOutput::Continue { event, allow_any } => { + allow_any_element = allow_any_element || allow_any; + event + } + ElementHandlerOutput::Break { event, allow_any } => { + break (event, allow_any) + } + } + } + (_, event @ Event::End(_)) => { + if let Some(fallback) = fallback.take() { + self.finish_state(helper, fallback)?; + } + return Ok(DeserializerOutput { + artifact: DeserializerArtifact::Data(self.finish(helper)?), + event: DeserializerEvent::Continue(event), + allow_any: false, + }); + } + (S::Init__, event) => { + fallback.get_or_insert(S::Init__); + *self.state__ = S::Info(None); + event + } + (S::Info(None), event @ (Event::Start(_) | Event::Empty(_))) => { + let output = helper.init_start_tag_deserializer( + event, + Some(&super::NS_TNS), + b"info", + false, + )?; + match self.handle_info(helper, output, &mut fallback)? { + ElementHandlerOutput::Continue { event, allow_any } => { + allow_any_element = allow_any_element || allow_any; + event + } + ElementHandlerOutput::Break { event, allow_any } => { + break (event, allow_any) + } + } + } + (S::Done__, event) => { + *self.state__ = S::Done__; + break (DeserializerEvent::Continue(event), allow_any_element); + } + (state, event) => { + *self.state__ = state; + break (DeserializerEvent::Break(event), false); + } + } + }; + if let Some(fallback) = fallback { + *self.state__ = fallback; + } + Ok(DeserializerOutput { + artifact: DeserializerArtifact::Deserializer(self), + event, + allow_any, + }) + } + fn finish( + mut self, + helper: &mut DeserializeHelper, + ) -> Result { + let state = replace( + &mut *self.state__, + FooContent2TypeDeserializerState::Unknown__, + ); + self.finish_state(helper, state)?; + Ok(super::FooContent2Type { + info: helper.finish_element("info", self.info)?, + }) + } + } + #[derive(Debug)] + pub struct BarTypeDeserializer { + content: Option, + state__: Box, + } + #[derive(Debug)] + enum BarTypeDeserializerState { + Init__, + Next__, + Content__(::Deserializer), + Unknown__, + } + impl BarTypeDeserializer { + fn from_bytes_start( + helper: &mut DeserializeHelper, + bytes_start: &BytesStart<'_>, + ) -> Result { + for attrib in helper.filter_xmlns_attributes(bytes_start) { + let attrib = attrib?; + helper.raise_unexpected_attrib_checked(&attrib)?; + } + Ok(Self { + content: None, + state__: Box::new(BarTypeDeserializerState::Init__), + }) + } + fn finish_state( + &mut self, + helper: &mut DeserializeHelper, + state: BarTypeDeserializerState, + ) -> Result<(), Error> { + if let BarTypeDeserializerState::Content__(deserializer) = state { + self.store_content(deserializer.finish(helper)?)?; + } + Ok(()) + } + fn store_content(&mut self, value: super::BarTypeContent) -> Result<(), Error> { + if self.content.is_some() { + Err(ErrorKind::DuplicateContent)?; + } + self.content = Some(value); + Ok(()) + } + fn handle_content<'de>( + &mut self, + helper: &mut DeserializeHelper, + output: DeserializerOutput<'de, super::BarTypeContent>, + fallback: &mut Option, + ) -> Result, Error> { + use BarTypeDeserializerState as S; + let DeserializerOutput { + artifact, + event, + allow_any, + } = output; + if artifact.is_none() { + *self.state__ = fallback.take().unwrap_or(S::Next__); + return Ok(ElementHandlerOutput::from_event_end(event, allow_any)); + } + if let Some(fallback) = fallback.take() { + self.finish_state(helper, fallback)?; + } + match artifact { + DeserializerArtifact::None => unreachable!(), + DeserializerArtifact::Data(data) => { + self.store_content(data)?; + *self.state__ = S::Next__; + Ok(ElementHandlerOutput::from_event(event, allow_any)) + } + DeserializerArtifact::Deserializer(deserializer) => { + *self.state__ = S::Content__(deserializer); + Ok(ElementHandlerOutput::from_event_end(event, allow_any)) + } + } + } + } + impl<'de> Deserializer<'de, super::BarType> for BarTypeDeserializer { + fn init( + helper: &mut DeserializeHelper, + event: Event<'de>, + ) -> DeserializerResult<'de, super::BarType> { + helper.init_deserializer_from_start_event(event, Self::from_bytes_start) + } + fn next( + mut self, + helper: &mut DeserializeHelper, + event: Event<'de>, + ) -> DeserializerResult<'de, super::BarType> { + use BarTypeDeserializerState as S; + let mut event = event; + let mut fallback = None; + let (event, allow_any) = loop { + let state = replace(&mut *self.state__, S::Unknown__); + event = match (state, event) { + (S::Unknown__, _) => unreachable!(), + (S::Content__(deserializer), event) => { + let output = deserializer.next(helper, event)?; + match self.handle_content(helper, output, &mut fallback)? { + ElementHandlerOutput::Break { event, allow_any } => { + break (event, allow_any) + } + ElementHandlerOutput::Continue { event, .. } => event, + } + } + (_, Event::End(_)) => { + return Ok(DeserializerOutput { + artifact: DeserializerArtifact::Data(self.finish(helper)?), + event: DeserializerEvent::None, + allow_any: false, + }); + } + (state @ (S::Init__ | S::Next__), event) => { + fallback.get_or_insert(state); + let output = + ::init(helper, event)?; + match self.handle_content(helper, output, &mut fallback)? { + ElementHandlerOutput::Break { event, allow_any } => { + break (event, allow_any) + } + ElementHandlerOutput::Continue { event, .. } => event, + } + } + } + }; + if let Some(fallback) = fallback { + *self.state__ = fallback; + } + let artifact = DeserializerArtifact::Deserializer(self); + Ok(DeserializerOutput { + artifact, + event, + allow_any, + }) + } + fn finish(mut self, helper: &mut DeserializeHelper) -> Result { + let state = replace(&mut *self.state__, BarTypeDeserializerState::Unknown__); + self.finish_state(helper, state)?; + Ok(super::BarType { + content: helper.finish_default(self.content)?, + }) + } + } + #[derive(Debug)] + pub struct BarTypeContentDeserializer { + state__: Box, + } + #[derive(Debug)] + pub enum BarTypeContentDeserializerState { + Init__, + Content4( + Vec, + Option<::Deserializer>, + Option<::Deserializer>, + ), + Done__(super::BarTypeContent), + Unknown__, + } + impl BarTypeContentDeserializer { + fn find_suitable<'de>( + &mut self, + helper: &mut DeserializeHelper, + event: Event<'de>, + ) -> Result, Error> { + let mut event = event; + let mut allow_any_element = false; + if let Event::Start(_) | Event::Empty(_) = &event { + event = { + let output = ::init(helper, event)?; + match self.handle_content_4(helper, Default::default(), None, output)? { + ElementHandlerOutput::Continue { event, allow_any } => { + allow_any_element = allow_any_element || allow_any; + event + } + output => { + return Ok(output); + } + } + }; + } + *self.state__ = BarTypeContentDeserializerState::Init__; + Ok(ElementHandlerOutput::return_to_parent( + event, + allow_any_element, + )) + } + fn finish_state( + helper: &mut DeserializeHelper, + state: BarTypeContentDeserializerState, + ) -> Result { + use BarTypeContentDeserializerState as S; + match state { + S::Init__ => Ok(super::BarTypeContent::Content4(Vec::new())), + S::Content4(mut values, None, deserializer) => { + if let Some(deserializer) = deserializer { + let value = deserializer.finish(helper)?; + Self::store_content_4(&mut values, value)?; + } + Ok(super::BarTypeContent::Content4(values)) + } + S::Done__(data) => Ok(data), + _ => unreachable!(), + } + } + fn store_content_4( + values: &mut Vec, + value: super::BarContent4Type, + ) -> Result<(), Error> { + values.push(value); + Ok(()) + } + fn handle_content_4<'de>( + &mut self, + helper: &mut DeserializeHelper, + mut values: Vec, + fallback: Option<::Deserializer>, + output: DeserializerOutput<'de, super::BarContent4Type>, + ) -> Result, Error> { + use BarTypeContentDeserializerState as S; + let DeserializerOutput { + artifact, + event, + allow_any, + } = output; + if artifact.is_none() { + if fallback.is_none() && values.is_empty() { + *self.state__ = S::Init__; + return Ok(ElementHandlerOutput::from_event(event, allow_any)); + } else { + *self.state__ = S::Content4(values, None, fallback); + return Ok(ElementHandlerOutput::break_(event, allow_any)); + } + } + if let Some(deserializer) = fallback { + let data = deserializer.finish(helper)?; + Self::store_content_4(&mut values, data)?; + } + match artifact { + DeserializerArtifact::None => unreachable!(), + DeserializerArtifact::Data(data) => { + Self::store_content_4(&mut values, data)?; + *self.state__ = S::Content4(values, None, None); + Ok(ElementHandlerOutput::from_event(event, allow_any)) + } + DeserializerArtifact::Deserializer(deserializer) => { + let ret = ElementHandlerOutput::from_event(event, allow_any); + if ret.is_continue_start_or_empty() { + *self.state__ = S::Content4(values, Some(deserializer), None); + } else { + *self.state__ = S::Content4(values, None, Some(deserializer)); + } + Ok(ret) + } + } + } + } + impl Default for BarTypeContentDeserializer { + fn default() -> Self { + Self { + state__: Box::new(BarTypeContentDeserializerState::Init__), + } + } + } + impl<'de> Deserializer<'de, super::BarTypeContent> for BarTypeContentDeserializer { + fn init( + helper: &mut DeserializeHelper, + event: Event<'de>, + ) -> DeserializerResult<'de, super::BarTypeContent> { + let deserializer = Self::default(); + let mut output = deserializer.next(helper, event)?; + output.artifact = match output.artifact { + DeserializerArtifact::Deserializer(x) + if matches!(&*x.state__, BarTypeContentDeserializerState::Init__) => + { + DeserializerArtifact::None + } + artifact => artifact, + }; + Ok(output) + } + fn next( + mut self, + helper: &mut DeserializeHelper, + event: Event<'de>, + ) -> DeserializerResult<'de, super::BarTypeContent> { + use BarTypeContentDeserializerState as S; + let mut event = event; + let (event, allow_any) = loop { + let state = replace(&mut *self.state__, S::Unknown__); + event = match (state, event) { + (S::Unknown__, _) => unreachable!(), + (S::Content4(values, fallback, Some(deserializer)), event) => { + let output = deserializer.next(helper, event)?; + match self.handle_content_4(helper, values, fallback, output)? { + ElementHandlerOutput::Break { event, allow_any } => { + break (event, allow_any) + } + ElementHandlerOutput::Continue { event, .. } => event, + } + } + (state, event @ Event::End(_)) => { + return Ok(DeserializerOutput { + artifact: DeserializerArtifact::Data(Self::finish_state( + helper, state, + )?), + event: DeserializerEvent::Continue(event), + allow_any: false, + }); + } + (S::Init__, event) => match self.find_suitable(helper, event)? { + ElementHandlerOutput::Break { event, allow_any } => { + break (event, allow_any) + } + ElementHandlerOutput::Continue { event, .. } => event, + }, + ( + S::Content4(values, fallback, None), + event @ (Event::Start(_) | Event::Empty(_)), + ) => { + let output = + ::init(helper, event)?; + match self.handle_content_4(helper, values, fallback, output)? { + ElementHandlerOutput::Break { event, allow_any } => { + break (event, allow_any) + } + ElementHandlerOutput::Continue { event, .. } => event, + } + } + (state @ S::Done__(_), event) => { + *self.state__ = state; + break (DeserializerEvent::Continue(event), false); + } + (state, event) => { + *self.state__ = state; + break (DeserializerEvent::Continue(event), false); + } + } + }; + let artifact = if matches!(&*self.state__, S::Done__(_)) { + DeserializerArtifact::Data(self.finish(helper)?) + } else { + DeserializerArtifact::Deserializer(self) + }; + Ok(DeserializerOutput { + artifact, + event, + allow_any, + }) + } + fn finish(self, helper: &mut DeserializeHelper) -> Result { + Self::finish_state(helper, *self.state__) + } + } + #[derive(Debug)] + pub struct BarContent4TypeDeserializer { + info: Option, + state__: Box, + } + #[derive(Debug)] + enum BarContent4TypeDeserializerState { + Init__, + Info(Option<::Deserializer>), + Done__, + Unknown__, + } + impl BarContent4TypeDeserializer { + fn finish_state( + &mut self, + helper: &mut DeserializeHelper, + state: BarContent4TypeDeserializerState, + ) -> Result<(), Error> { + use BarContent4TypeDeserializerState as S; + match state { + S::Info(Some(deserializer)) => self.store_info(deserializer.finish(helper)?)?, + _ => (), + } + Ok(()) + } + fn store_info(&mut self, value: String) -> Result<(), Error> { + if self.info.is_some() { + Err(ErrorKind::DuplicateElement(RawByteStr::from_slice(b"info")))?; + } + self.info = Some(value); + Ok(()) + } + fn handle_info<'de>( + &mut self, + helper: &mut DeserializeHelper, + output: DeserializerOutput<'de, String>, + fallback: &mut Option, + ) -> Result, Error> { + use BarContent4TypeDeserializerState as S; + let DeserializerOutput { + artifact, + event, + allow_any, + } = output; + if artifact.is_none() { + fallback.get_or_insert(S::Info(None)); + if matches!(&fallback, Some(S::Init__)) { + return Ok(ElementHandlerOutput::break_(event, allow_any)); + } else { + return Ok(ElementHandlerOutput::return_to_root(event, allow_any)); + } + } + if let Some(fallback) = fallback.take() { + self.finish_state(helper, fallback)?; + } + match artifact { + DeserializerArtifact::None => unreachable!(), + DeserializerArtifact::Data(data) => { + self.store_info(data)?; + *self.state__ = S::Done__; + Ok(ElementHandlerOutput::from_event(event, allow_any)) + } + DeserializerArtifact::Deserializer(deserializer) => { + fallback.get_or_insert(S::Info(Some(deserializer))); + *self.state__ = S::Done__; + Ok(ElementHandlerOutput::from_event(event, allow_any)) + } + } + } + } + impl<'de> Deserializer<'de, super::BarContent4Type> for BarContent4TypeDeserializer { + fn init( + helper: &mut DeserializeHelper, + event: Event<'de>, + ) -> DeserializerResult<'de, super::BarContent4Type> { + let deserializer = Self { + info: None, + state__: Box::new(BarContent4TypeDeserializerState::Init__), + }; + let mut output = deserializer.next(helper, event)?; + output.artifact = match output.artifact { + DeserializerArtifact::Deserializer(x) + if matches!(&*x.state__, BarContent4TypeDeserializerState::Init__) => + { + DeserializerArtifact::None + } + artifact => artifact, + }; + Ok(output) + } + fn next( + mut self, + helper: &mut DeserializeHelper, + event: Event<'de>, + ) -> DeserializerResult<'de, super::BarContent4Type> { + use BarContent4TypeDeserializerState as S; + let mut event = event; + let mut fallback = None; + let mut allow_any_element = false; + let (event, allow_any) = loop { + let state = replace(&mut *self.state__, S::Unknown__); + event = match (state, event) { + (S::Unknown__, _) => unreachable!(), + (S::Info(Some(deserializer)), event) => { + let output = deserializer.next(helper, event)?; + match self.handle_info(helper, output, &mut fallback)? { + ElementHandlerOutput::Continue { event, allow_any } => { + allow_any_element = allow_any_element || allow_any; + event + } + ElementHandlerOutput::Break { event, allow_any } => { + break (event, allow_any) + } + } + } + (_, event @ Event::End(_)) => { + if let Some(fallback) = fallback.take() { + self.finish_state(helper, fallback)?; + } + return Ok(DeserializerOutput { + artifact: DeserializerArtifact::Data(self.finish(helper)?), + event: DeserializerEvent::Continue(event), + allow_any: false, + }); + } + (S::Init__, event) => { + fallback.get_or_insert(S::Init__); + *self.state__ = S::Info(None); + event + } + (S::Info(None), event @ (Event::Start(_) | Event::Empty(_))) => { + let output = helper.init_start_tag_deserializer( + event, + Some(&super::NS_TNS), + b"info", + false, + )?; + match self.handle_info(helper, output, &mut fallback)? { + ElementHandlerOutput::Continue { event, allow_any } => { + allow_any_element = allow_any_element || allow_any; + event + } + ElementHandlerOutput::Break { event, allow_any } => { + break (event, allow_any) + } + } + } + (S::Done__, event) => { + *self.state__ = S::Done__; + break (DeserializerEvent::Continue(event), allow_any_element); + } + (state, event) => { + *self.state__ = state; + break (DeserializerEvent::Break(event), false); + } + } + }; + if let Some(fallback) = fallback { + *self.state__ = fallback; + } + Ok(DeserializerOutput { + artifact: DeserializerArtifact::Deserializer(self), + event, + allow_any, + }) + } + fn finish( + mut self, + helper: &mut DeserializeHelper, + ) -> Result { + let state = replace( + &mut *self.state__, + BarContent4TypeDeserializerState::Unknown__, + ); + self.finish_state(helper, state)?; + Ok(super::BarContent4Type { + info: helper.finish_element("info", self.info)?, + }) + } + } +} diff --git a/xsd-parser/tests/feature/choice_single_option_defaults/mod.rs b/xsd-parser/tests/feature/choice_single_option_defaults/mod.rs new file mode 100644 index 00000000..5f6f7d07 --- /dev/null +++ b/xsd-parser/tests/feature/choice_single_option_defaults/mod.rs @@ -0,0 +1,86 @@ +/* + * Tests how quick_xml deserialization handles enums that come from an + * xs:choice, when that enum has only one variant, and that variant is + * a group. Previously the logic for determining what could implement + * Default in this scenario was incomplete, creating code that couldn't + * compile due to a missing Default impl. In the provided schema, one + * element has an xs:choice that is defaultable and the other has one + * one that isn't + */ + +use xsd_parser::{Config, IdentType}; + +use crate::utils::{generate_test, ConfigEx}; + +fn config() -> Config { + Config::test_default().with_generate([ + (IdentType::Element, "tns:foo"), + (IdentType::Element, "tns:bar"), + ]) +} + +#[test] +fn generate_default() { + generate_test( + "tests/feature/choice_single_option_defaults/schema.xsd", + "tests/feature/choice_single_option_defaults/expected/default.rs", + config(), + ); +} + +#[cfg(not(feature = "update-expectations"))] +mod default { + #![allow(unused_imports)] + include!("expected/default.rs"); +} + +#[test] +fn generate_quick_xml() { + generate_test( + "tests/feature/choice_single_option_defaults/schema.xsd", + "tests/feature/choice_single_option_defaults/expected/quick_xml.rs", + config().with_quick_xml_deserialize(), + ); +} + +#[cfg(not(feature = "update-expectations"))] +mod quick_xml { + #![allow(unused_imports)] + include!("expected/quick_xml.rs"); +} + +#[cfg(not(feature = "update-expectations"))] +#[test] +fn read_quick_xml_defaultable() { + use quick_xml::Bar; + use quick_xml::BarTypeContent; + let obj = crate::utils::quick_xml_read_test::( + "tests/feature/choice_single_option_defaults/example/defaultable.xml", + ); + let expected = Bar { + content: BarTypeContent::Content4(vec![]), + }; + assert!(matches!(obj, expected)) +} + +#[cfg(not(feature = "update-expectations"))] +#[test] +fn read_quick_xml_not_defaultable() { + use quick_xml::Foo; + use quick_xml::FooContent2Type; + use quick_xml::FooTypeContent; + let obj = crate::utils::quick_xml_read_test::( + "tests/feature/choice_single_option_defaults/example/not_defaultable.xml", + ); + let expected = Foo { + content: FooTypeContent::Content2(vec![ + FooContent2Type { + info: "test 1".into(), + }, + FooContent2Type { + info: "test 2".into(), + }, + ]), + }; + assert!(matches!(obj, expected)) +} diff --git a/xsd-parser/tests/feature/choice_single_option_defaults/schema.xsd b/xsd-parser/tests/feature/choice_single_option_defaults/schema.xsd new file mode 100644 index 00000000..2cf00641 --- /dev/null +++ b/xsd-parser/tests/feature/choice_single_option_defaults/schema.xsd @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xsd-parser/tests/feature/mod.rs b/xsd-parser/tests/feature/mod.rs index 872f94be..c9b2d29a 100644 --- a/xsd-parser/tests/feature/mod.rs +++ b/xsd-parser/tests/feature/mod.rs @@ -11,6 +11,7 @@ mod attribute; mod build_in; mod choice; mod choice_flatten_content; +mod choice_single_option_defaults; mod choice_with_sequence; mod complex_type_empty; mod complex_type_with_group;