1use super::XmlCodecSettings;
9use crate::decode::{self, Document};
10use aws_smithy_schema::serde::{SerdeError, ShapeDeserializer};
11use aws_smithy_schema::Schema;
12use aws_smithy_types::date_time::Format as TimestampFormat;
13use aws_smithy_types::{BigDecimal, BigInteger, Blob, DateTime};
14
15use aws_smithy_types::Document as SmithyDocument;
16use std::borrow::Cow;
17use std::sync::Arc;
18
19pub(crate) const MAX_DESERIALIZE_DEPTH: u32 = 128;
23
24pub struct XmlDeserializer<'a> {
41 input: &'a [u8],
45 text: Option<Result<Cow<'a, str>, SerdeError>>,
49 settings: Arc<XmlCodecSettings>,
50 depth: u32,
56}
57
58impl<'a> XmlDeserializer<'a> {
59 pub(crate) fn new(input: &'a [u8], settings: Arc<XmlCodecSettings>) -> Self {
61 Self {
62 input,
63 text: None,
64 settings,
65 depth: 0,
66 }
67 }
68
69 fn new_child<'b>(&self, input: &'b [u8]) -> XmlDeserializer<'b> {
82 XmlDeserializer {
83 input,
84 text: None,
85 settings: self.settings.clone(),
86 depth: self.depth,
87 }
88 }
89
90 #[cfg(test)]
95 fn from_text(text: Cow<'a, str>, settings: Arc<XmlCodecSettings>) -> Self {
96 Self {
97 input: b"",
98 text: Some(Ok(text)),
99 settings,
100 depth: 0,
101 }
102 }
103
104 fn enter_aggregate(&mut self) -> Result<(), SerdeError> {
114 if self.depth >= self.settings.max_depth() {
115 return Err(SerdeError::custom("maximum nesting depth exceeded"));
116 }
117 self.depth += 1;
118 Ok(())
119 }
120
121 fn leave_aggregate(&mut self) {
124 debug_assert!(self.depth > 0, "leave_aggregate without enter_aggregate");
125 self.depth = self.depth.saturating_sub(1);
126 }
127
128 fn document(&self) -> Result<Document<'a>, SerdeError> {
132 if self.text.is_some() {
133 return Err(SerdeError::custom("expected XML element, found text"));
134 }
135 let mut doc = Document::try_from(self.input).unwrap_or_else(|_| Document::new(""));
136 if self.settings.validate_document && self.depth == 1 {
137 doc.check_well_formedness();
138 }
139 Ok(doc)
140 }
141
142 fn take_text(&mut self) -> Result<Cow<'a, str>, SerdeError> {
146 if let Some(t) = self.text.take() {
147 return t;
148 }
149 let mut doc = Document::try_from(self.input).unwrap_or_else(|_| Document::new(""));
150 let top_level_strict = self.settings.validate_document && self.depth == 0;
151 if top_level_strict {
152 doc.check_well_formedness();
153 }
154 let mut root = doc
155 .root_element()
156 .map_err(|e| SerdeError::custom(e.to_string()))?;
157 let text = decode::try_data(&mut root).map_err(|e| SerdeError::custom(e.to_string()))?;
158 drop(root);
159 if top_level_strict {
160 Self::finish_well_formed(&mut doc)?;
161 }
162 Ok(text)
163 }
164
165 fn dispatch_subslice<R>(&mut self, sub: &'a [u8], f: impl FnOnce(&mut Self) -> R) -> R {
170 let saved_input = std::mem::replace(&mut self.input, sub);
171 let saved_text = self.text.take();
172 let r = f(self);
173 self.input = saved_input;
174 self.text = saved_text;
175 r
176 }
177
178 fn dispatch_text<R>(
182 &mut self,
183 text: Result<Cow<'a, str>, SerdeError>,
184 f: impl FnOnce(&mut Self) -> R,
185 ) -> R {
186 let saved_input = std::mem::replace(&mut self.input, b"");
187 let saved_text = self.text.replace(text);
188 let r = f(self);
189 self.input = saved_input;
190 self.text = saved_text;
191 r
192 }
193
194 fn resolve_member<'s>(schema: &'s Schema<'s>, element_name: &str) -> Option<&'s Schema<'s>> {
198 schema.members().iter().copied().find(|m| {
199 if let Some(xml_name) = m.xml_name() {
200 xml_name.value() == element_name
201 } else {
202 m.member_name() == Some(element_name)
203 }
204 })
205 }
206
207 fn list_item_name<'s>(check_names: bool, schema: &'s Schema<'_>) -> Option<&'s str> {
219 if !check_names || schema.xml_flattened() {
220 return None;
221 }
222 let member = schema.member()?;
223 Some(
224 member
225 .xml_name()
226 .map(|t| t.value())
227 .or(member.member_name())
228 .unwrap_or("member"),
229 )
230 }
231
232 fn is_list_item(item_name: Option<&str>, el: &decode::StartEl<'_>) -> bool {
236 item_name.is_none_or(|name| el.matches(name))
237 }
238
239 fn is_map_entry(check_names: bool, schema: &Schema<'_>, el: &decode::StartEl<'_>) -> bool {
245 !check_names || schema.xml_flattened() || el.matches("entry")
246 }
247
248 fn element_start(input: &[u8], el_local: &str) -> usize {
263 let input_start = input.as_ptr() as usize;
264 let name_ptr = el_local.as_ptr() as usize;
265 debug_assert!(
266 name_ptr >= input_start && name_ptr + el_local.len() <= input_start + input.len(),
267 "element_start: el_local must point into input"
268 );
269 let name_offset = name_ptr.saturating_sub(input_start).min(input.len());
270 input[..name_offset]
271 .iter()
272 .rposition(|&b| b == b'<')
273 .unwrap_or(0)
274 }
275
276 fn finish_well_formed(doc: &mut Document<'_>) -> Result<(), SerdeError> {
279 doc.finish_well_formed()
280 .map_err(|e| SerdeError::invalid_input(format!("ill-formed XML: {e}")))
281 }
282
283 fn finish_document(&self, doc: &mut Document<'_>) -> Result<(), SerdeError> {
286 if self.settings.validate_document && self.depth == 1 {
287 Self::finish_well_formed(doc)?;
288 }
289 Ok(())
290 }
291
292 fn resolve_timestamp_format(&self, schema: &Schema<'_>) -> Result<TimestampFormat, SerdeError> {
293 let Some(t) = schema.timestamp_format() else {
294 return Ok(match self.settings.default_timestamp_format() {
295 TimestampFormat::DateTime => TimestampFormat::DateTimeWithOffset,
296 other => other,
297 });
298 };
299 Ok(match t.format() {
300 aws_smithy_schema::traits::TimestampFormat::EpochSeconds => {
301 TimestampFormat::EpochSeconds
302 }
303 aws_smithy_schema::traits::TimestampFormat::DateTime => {
308 TimestampFormat::DateTimeWithOffset
309 }
310 aws_smithy_schema::traits::TimestampFormat::HttpDate => TimestampFormat::HttpDate,
311 other => {
312 return Err(SerdeError::unsupported(format!(
313 "unsupported timestamp format {other:?}"
314 )))
315 }
316 })
317 }
318}
319
320pub fn find_depth2_element_slice_by(
334 body: &[u8],
335 predicate: impl Fn(&str) -> bool,
336) -> Option<&[u8]> {
337 let mut doc = Document::try_from(body).ok()?;
338 let mut root = doc.root_element().ok()?;
339 if predicate(root.start_el().local()) {
342 return Some(body);
343 }
344 while let Some(tag) = root.next_tag() {
346 let local = tag.start_el().local();
347 if predicate(local) {
348 let start = XmlDeserializer::element_start(body, local);
351 return Some(&body[start..tag.end_offset()]);
352 }
353 }
354 None
355}
356
357impl ShapeDeserializer for XmlDeserializer<'_> {
358 fn read_struct(
359 &mut self,
360 schema: &Schema<'_>,
361 consumer: &mut dyn FnMut(&Schema<'_>, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
362 ) -> Result<(), SerdeError> {
363 self.enter_aggregate()?;
364 let result = (|| -> Result<(), SerdeError> {
370 let input = self.input;
376 let mut doc = self.document()?;
383 let mut root = doc
384 .root_element()
385 .map_err(|e| SerdeError::custom(e.to_string()))?;
386
387 if self.settings.validate_root_name && self.depth == 1 {
388 let expected = schema
389 .xml_name()
390 .map(|t| t.value())
391 .or_else(|| schema.original_name())
392 .or_else(|| schema.member_name())
393 .unwrap_or_else(|| schema.shape_id().shape_name());
394 if !root.start_el().matches(expected) {
395 return Err(SerdeError::invalid_input(format!(
396 "expected XML root {expected}"
397 )));
398 }
399 }
400
401 if schema.xml_unwrapped_output() {
410 let el_local = root.start_el().local();
418 let start = Self::element_start(input, el_local);
419 let local = el_local.to_owned();
420 let sub = &input[start..root.end_offset()];
424 self.finish_document(&mut doc)?;
425 if let Some(member) = Self::resolve_member(schema, &local) {
426 self.dispatch_subslice(sub, |this| consumer(member, this))?;
427 }
428 return Ok(());
429 }
430
431 for member in schema.members() {
433 if member.xml_attribute() {
434 let attr_name = member
435 .xml_name()
436 .map(|t| t.value())
437 .or(member.member_name())
438 .unwrap_or("");
439 if let Some(value) = root.start_el().attr(attr_name) {
440 let text = Cow::Owned(value.to_owned());
441 self.dispatch_text(Ok(text), |this| consumer(member, this))?;
442 }
443 }
444 }
445
446 let mut flattened_groups: std::collections::HashMap<usize, (&Schema<'_>, Vec<u8>)> =
450 std::collections::HashMap::new();
451
452 while let Some(mut child_scope) = root.next_tag() {
454 let Some(member) = Self::resolve_member(schema, child_scope.start_el().local())
455 else {
456 continue;
457 };
458 let is_aggregate = member.shape_type().is_aggregate();
466 if is_aggregate && !member.xml_flattened() {
467 let start = Self::element_start(input, child_scope.start_el().local());
468 let sub = &input[start..child_scope.end_offset()];
469 self.dispatch_subslice(sub, |this| consumer(member, this))?;
470 } else if is_aggregate {
471 let start = Self::element_start(input, child_scope.start_el().local());
474 let sub = &input[start..child_scope.end_offset()];
475 let idx = member.member_index().unwrap_or(usize::MAX);
476 let entry = flattened_groups
477 .entry(idx)
478 .or_insert_with(|| (member, Vec::new()));
479 entry.1.extend_from_slice(sub);
480 } else {
481 let text = decode::try_data(&mut child_scope)
484 .map_err(|e| SerdeError::custom(e.to_string()));
485 drop(child_scope);
486 self.dispatch_text(text, |this| consumer(member, this))?;
487 }
488 }
489 drop(root);
490 self.finish_document(&mut doc)?;
491
492 for (_idx, (member, bytes)) in flattened_groups {
501 let mut wrapped = Vec::with_capacity(bytes.len() + 16);
502 wrapped.extend_from_slice(b"<__flat>");
503 wrapped.extend_from_slice(&bytes);
504 wrapped.extend_from_slice(b"</__flat>");
505 let mut child_deser = self.new_child(&wrapped);
506 consumer(member, &mut child_deser)?;
507 }
508 Ok(())
509 })();
510 self.leave_aggregate();
511 result
512 }
513
514 fn read_list(
515 &mut self,
516 schema: &Schema<'_>,
517 consumer: &mut dyn FnMut(&mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
518 ) -> Result<(), SerdeError> {
519 let item_name = Self::list_item_name(self.settings.strict_collection_element_names, schema);
520 self.enter_aggregate()?;
521 let result = (|| -> Result<(), SerdeError> {
524 let input = self.input;
525 let mut doc = self.document()?;
526 let mut root = doc
527 .root_element()
528 .map_err(|e| SerdeError::custom(e.to_string()))?;
529
530 while let Some(child_scope) = root.next_tag() {
540 if !Self::is_list_item(item_name, child_scope.start_el()) {
541 continue;
542 }
543 let start = Self::element_start(input, child_scope.start_el().local());
544 let sub = &input[start..child_scope.end_offset()];
545 self.dispatch_subslice(sub, |this| consumer(this))?;
546 }
547 drop(root);
548 self.finish_document(&mut doc)?;
549 Ok(())
550 })();
551 self.leave_aggregate();
552 result
553 }
554
555 fn read_map(
556 &mut self,
557 schema: &Schema<'_>,
558 consumer: &mut dyn FnMut(String, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
559 ) -> Result<(), SerdeError> {
560 self.enter_aggregate()?;
561 let result = (|| -> Result<(), SerdeError> {
564 let input = self.input;
565 let mut doc = self.document()?;
566 let mut root = doc
567 .root_element()
568 .map_err(|e| SerdeError::custom(e.to_string()))?;
569
570 let key_name = schema
572 .key()
573 .and_then(|k| k.xml_name().map(|t| t.value()))
574 .unwrap_or("key");
575 let value_name = schema
576 .member()
577 .and_then(|v| v.xml_name().map(|t| t.value()))
578 .unwrap_or("value");
579
580 let value_is_aggregate = schema
583 .member()
584 .map(|v| v.shape_type().is_aggregate())
585 .unwrap_or(false);
586
587 while let Some(mut entry_scope) = root.next_tag() {
591 if !Self::is_map_entry(
592 self.settings.strict_collection_element_names,
593 schema,
594 entry_scope.start_el(),
595 ) {
596 continue;
597 }
598 let mut key: Option<String> = None;
599 let mut value_text: Option<Cow<'_, str>> = None;
602 let mut value_slice: Option<&'_ [u8]> = None;
603 while let Some(mut field_scope) = entry_scope.next_tag() {
604 let local = field_scope.start_el().local();
605 let (is_key, is_value) = (local == key_name, local == value_name);
606 if is_key {
607 let text = decode::try_data(&mut field_scope)
608 .map_err(|e| SerdeError::custom(e.to_string()))?;
609 key = Some(text.into_owned());
610 } else if is_value {
611 if value_is_aggregate {
612 let start = Self::element_start(input, field_scope.start_el().local());
613 let sub = &input[start..field_scope.end_offset()];
614 value_slice = Some(sub);
615 } else {
616 let text = decode::try_data(&mut field_scope)
617 .map_err(|e| SerdeError::custom(e.to_string()))?;
618 value_text = Some(text);
619 }
620 }
621 }
622 drop(entry_scope);
623 if let Some(k) = key {
624 if let Some(slice) = value_slice {
625 self.dispatch_subslice(slice, |this| consumer(k, this))?;
626 } else if let Some(t) = value_text {
627 let t: Cow<'_, str> = t;
631 self.dispatch_text(Ok(t.into_owned().into()), |this| consumer(k, this))?;
632 }
633 }
634 }
635 drop(root);
636 self.finish_document(&mut doc)?;
637 Ok(())
638 })();
639 self.leave_aggregate();
640 result
641 }
642
643 fn read_boolean(&mut self, _schema: &Schema<'_>) -> Result<bool, SerdeError> {
644 let text = self.take_text()?;
645 match text.as_ref() {
646 "true" => Ok(true),
647 "false" => Ok(false),
648 other => Err(SerdeError::custom(format!("invalid boolean: {other}"))),
649 }
650 }
651
652 fn read_byte(&mut self, _schema: &Schema<'_>) -> Result<i8, SerdeError> {
653 let text = self.take_text()?;
654 text.parse().map_err(|e| SerdeError::custom(format!("{e}")))
655 }
656
657 fn read_short(&mut self, _schema: &Schema<'_>) -> Result<i16, SerdeError> {
658 let text = self.take_text()?;
659 text.parse().map_err(|e| SerdeError::custom(format!("{e}")))
660 }
661
662 fn read_integer(&mut self, _schema: &Schema<'_>) -> Result<i32, SerdeError> {
663 let text = self.take_text()?;
664 text.parse().map_err(|e| SerdeError::custom(format!("{e}")))
665 }
666
667 fn read_long(&mut self, _schema: &Schema<'_>) -> Result<i64, SerdeError> {
668 let text = self.take_text()?;
669 text.parse().map_err(|e| SerdeError::custom(format!("{e}")))
670 }
671
672 fn read_float(&mut self, _schema: &Schema<'_>) -> Result<f32, SerdeError> {
673 let text = self.take_text()?;
674 match text.as_ref() {
675 "NaN" => Ok(f32::NAN),
676 "Infinity" => Ok(f32::INFINITY),
677 "-Infinity" => Ok(f32::NEG_INFINITY),
678 _ => text.parse().map_err(|e| SerdeError::custom(format!("{e}"))),
679 }
680 }
681
682 fn read_double(&mut self, _schema: &Schema<'_>) -> Result<f64, SerdeError> {
683 let text = self.take_text()?;
684 match text.as_ref() {
685 "NaN" => Ok(f64::NAN),
686 "Infinity" => Ok(f64::INFINITY),
687 "-Infinity" => Ok(f64::NEG_INFINITY),
688 _ => text.parse().map_err(|e| SerdeError::custom(format!("{e}"))),
689 }
690 }
691
692 fn read_big_integer(&mut self, _schema: &Schema<'_>) -> Result<BigInteger, SerdeError> {
693 let text = self.take_text()?;
694 text.parse().map_err(|e| SerdeError::custom(format!("{e}")))
695 }
696
697 fn read_big_decimal(&mut self, _schema: &Schema<'_>) -> Result<BigDecimal, SerdeError> {
698 let text = self.take_text()?;
699 text.parse().map_err(|e| SerdeError::custom(format!("{e}")))
700 }
701
702 fn read_string(&mut self, _schema: &Schema<'_>) -> Result<String, SerdeError> {
703 let text = self.take_text()?;
704 Ok(text.into_owned())
705 }
706
707 fn read_blob(&mut self, _schema: &Schema<'_>) -> Result<Blob, SerdeError> {
708 let text = self.take_text()?;
709 let bytes = aws_smithy_types::base64::decode(text.as_ref())
710 .map_err(|e| SerdeError::custom(format!("{e}")))?;
711 Ok(Blob::new(bytes))
712 }
713
714 fn read_timestamp(&mut self, schema: &Schema<'_>) -> Result<DateTime, SerdeError> {
715 let text = self.take_text()?;
716 let format = self.resolve_timestamp_format(schema)?;
717 DateTime::from_str(text.as_ref(), format).map_err(|e| SerdeError::custom(format!("{e}")))
718 }
719
720 fn read_document(&mut self, _schema: &Schema<'_>) -> Result<SmithyDocument, SerdeError> {
721 Err(SerdeError::custom(
722 "document types are not supported by REST XML",
723 ))
724 }
725
726 fn read_string_list(&mut self, schema: &Schema<'_>) -> Result<Vec<String>, SerdeError> {
752 let item_name = Self::list_item_name(self.settings.strict_collection_element_names, schema);
753 self.enter_aggregate()?;
754 let result = (|| -> Result<Vec<String>, SerdeError> {
759 let mut doc = self.document()?;
760 let mut root = doc
761 .root_element()
762 .map_err(|e| SerdeError::custom(e.to_string()))?;
763 let mut out = Vec::new();
764 while let Some(mut child_scope) = root.next_tag() {
765 if !Self::is_list_item(item_name, child_scope.start_el()) {
766 continue;
767 }
768 let text = decode::try_data(&mut child_scope)
769 .map_err(|e| SerdeError::custom(e.to_string()))?;
770 out.push(text.into_owned());
771 }
772 drop(root);
773 self.finish_document(&mut doc)?;
774 Ok(out)
775 })();
776 self.leave_aggregate();
777 result
778 }
779
780 fn read_blob_list(&mut self, schema: &Schema<'_>) -> Result<Vec<Blob>, SerdeError> {
781 use aws_smithy_types::base64;
782 let item_name = Self::list_item_name(self.settings.strict_collection_element_names, schema);
783 self.enter_aggregate()?;
784 let result = (|| -> Result<Vec<Blob>, SerdeError> {
785 let mut doc = self.document()?;
786 let mut root = doc
787 .root_element()
788 .map_err(|e| SerdeError::custom(e.to_string()))?;
789 let mut out = Vec::new();
790 while let Some(mut child_scope) = root.next_tag() {
791 if !Self::is_list_item(item_name, child_scope.start_el()) {
792 continue;
793 }
794 let text = decode::try_data(&mut child_scope)
795 .map_err(|e| SerdeError::custom(e.to_string()))?;
796 let bytes = base64::decode(text.as_ref())
797 .map_err(|e| SerdeError::custom(format!("invalid base64: {e}")))?;
798 out.push(Blob::new(bytes));
799 }
800 drop(root);
801 self.finish_document(&mut doc)?;
802 Ok(out)
803 })();
804 self.leave_aggregate();
805 result
806 }
807
808 fn read_integer_list(&mut self, schema: &Schema<'_>) -> Result<Vec<i32>, SerdeError> {
809 let item_name = Self::list_item_name(self.settings.strict_collection_element_names, schema);
810 self.enter_aggregate()?;
811 let result = (|| -> Result<Vec<i32>, SerdeError> {
812 let mut doc = self.document()?;
813 let mut root = doc
814 .root_element()
815 .map_err(|e| SerdeError::custom(e.to_string()))?;
816 let mut out = Vec::new();
817 while let Some(mut child_scope) = root.next_tag() {
818 if !Self::is_list_item(item_name, child_scope.start_el()) {
819 continue;
820 }
821 let text = decode::try_data(&mut child_scope)
822 .map_err(|e| SerdeError::custom(e.to_string()))?;
823 let v: i32 = text
824 .parse()
825 .map_err(|e| SerdeError::custom(format!("{e}")))?;
826 out.push(v);
827 }
828 drop(root);
829 self.finish_document(&mut doc)?;
830 Ok(out)
831 })();
832 self.leave_aggregate();
833 result
834 }
835
836 fn read_long_list(&mut self, schema: &Schema<'_>) -> Result<Vec<i64>, SerdeError> {
837 let item_name = Self::list_item_name(self.settings.strict_collection_element_names, schema);
838 self.enter_aggregate()?;
839 let result = (|| -> Result<Vec<i64>, SerdeError> {
840 let mut doc = self.document()?;
841 let mut root = doc
842 .root_element()
843 .map_err(|e| SerdeError::custom(e.to_string()))?;
844 let mut out = Vec::new();
845 while let Some(mut child_scope) = root.next_tag() {
846 if !Self::is_list_item(item_name, child_scope.start_el()) {
847 continue;
848 }
849 let text = decode::try_data(&mut child_scope)
850 .map_err(|e| SerdeError::custom(e.to_string()))?;
851 let v: i64 = text
852 .parse()
853 .map_err(|e| SerdeError::custom(format!("{e}")))?;
854 out.push(v);
855 }
856 drop(root);
857 self.finish_document(&mut doc)?;
858 Ok(out)
859 })();
860 self.leave_aggregate();
861 result
862 }
863
864 fn read_string_string_map(
865 &mut self,
866 schema: &Schema<'_>,
867 ) -> Result<std::collections::HashMap<String, String>, SerdeError> {
868 let key_name = schema
869 .key()
870 .and_then(|k| k.xml_name().map(|t| t.value()))
871 .unwrap_or("key");
872 let value_name = schema
873 .member()
874 .and_then(|v| v.xml_name().map(|t| t.value()))
875 .unwrap_or("value");
876
877 self.enter_aggregate()?;
878 let result = (|| -> Result<std::collections::HashMap<String, String>, SerdeError> {
879 let mut doc = self.document()?;
880 let mut root = doc
881 .root_element()
882 .map_err(|e| SerdeError::custom(e.to_string()))?;
883 let mut out = std::collections::HashMap::new();
884 while let Some(mut entry_scope) = root.next_tag() {
885 if !Self::is_map_entry(
886 self.settings.strict_collection_element_names,
887 schema,
888 entry_scope.start_el(),
889 ) {
890 continue;
891 }
892 let mut k: Option<String> = None;
893 let mut v: Option<String> = None;
894 while let Some(mut field_scope) = entry_scope.next_tag() {
895 let local = field_scope.start_el().local();
896 let (is_key, is_value) = (local == key_name, local == value_name);
897 if is_key {
898 let text = decode::try_data(&mut field_scope)
899 .map_err(|e| SerdeError::custom(e.to_string()))?;
900 k = Some(text.into_owned());
901 } else if is_value {
902 let text = decode::try_data(&mut field_scope)
903 .map_err(|e| SerdeError::custom(e.to_string()))?;
904 v = Some(text.into_owned());
905 }
906 }
907 if let (Some(k), Some(v)) = (k, v) {
908 out.insert(k, v);
909 }
910 }
911 drop(root);
912 self.finish_document(&mut doc)?;
913 Ok(out)
914 })();
915 self.leave_aggregate();
916 result
917 }
918
919 fn is_null(&self) -> bool {
920 false
923 }
924
925 fn skip_value(&mut self) -> Result<(), SerdeError> {
931 Ok(())
932 }
933
934 fn container_size(&self) -> Option<usize> {
935 None
936 }
937}
938
939#[cfg(test)]
940mod tests {
941 use super::*;
942 use aws_smithy_schema::{shape_id, Schema, ShapeType};
943
944 static STRING_MEMBER: Schema<'static> =
945 Schema::new_member(shape_id!("test", "S$v"), ShapeType::String, "v", 0);
946
947 #[test]
948 fn read_string_from_text_state() {
949 let settings = Arc::new(XmlCodecSettings::default());
950 let mut deser = XmlDeserializer::from_text(Cow::Borrowed("hello"), settings);
951 let result = deser.read_string(&STRING_MEMBER).unwrap();
952 assert_eq!(result, "hello");
953 }
954
955 #[test]
956 fn read_string_from_doc_text_content() {
957 static V_MEMBER: Schema<'static> =
961 Schema::new_member(shape_id!("test", "X$v"), ShapeType::String, "v", 0);
962 let xml = b"<root>world</root>";
963 let settings = Arc::new(XmlCodecSettings::default());
964 let mut deser = XmlDeserializer::new(xml, settings);
965 let result = deser.read_string(&V_MEMBER).unwrap();
966 assert_eq!(result, "world");
967 }
968
969 #[test]
970 fn is_null_always_false() {
971 let settings = Arc::new(XmlCodecSettings::default());
972 let deser = XmlDeserializer::new(b"<r/>", settings);
973 assert!(!deser.is_null());
974 }
975
976 static NAME_MEMBER: Schema<'static> = Schema::new_member(
979 shape_id!("test", "Person$name"),
980 ShapeType::String,
981 "name",
982 0,
983 );
984 static AGE_MEMBER: Schema<'static> =
985 Schema::new_member(shape_id!("test", "Person$age"), ShapeType::String, "age", 1);
986 static RENAMED_MEMBER: Schema<'static> = Schema::new_member(
987 shape_id!("test", "Person$nick"),
988 ShapeType::String,
989 "nick",
990 2,
991 )
992 .with_xml_name("Nickname");
993
994 static PERSON_SCHEMA: Schema<'static> = Schema::new_struct(
995 shape_id!("test", "Person"),
996 ShapeType::Structure,
997 &[&NAME_MEMBER, &AGE_MEMBER, &RENAMED_MEMBER],
998 );
999
1000 #[test]
1001 fn read_struct_dispatches_members() {
1002 let xml = b"<Person><name>Alice</name><age>30</age></Person>";
1003 let settings = Arc::new(XmlCodecSettings::default());
1004 let mut deser = XmlDeserializer::new(xml, settings);
1005
1006 let mut name = String::new();
1007 let mut age = String::new();
1008 deser
1009 .read_struct(&PERSON_SCHEMA, &mut |member, d| {
1010 match member.member_name().unwrap() {
1011 "name" => name = d.read_string(member)?,
1012 "age" => age = d.read_string(member)?,
1013 _ => {}
1014 }
1015 Ok(())
1016 })
1017 .unwrap();
1018
1019 assert_eq!(name, "Alice");
1020 assert_eq!(age, "30");
1021 }
1022
1023 #[test]
1024 fn read_struct_skips_unknown_elements() {
1025 let xml = b"<Person><unknown>x</unknown><name>Bob</name></Person>";
1026 let settings = Arc::new(XmlCodecSettings::default());
1027 let mut deser = XmlDeserializer::new(xml, settings);
1028
1029 let mut name = String::new();
1030 deser
1031 .read_struct(&PERSON_SCHEMA, &mut |member, d| {
1032 if member.member_name() == Some("name") {
1033 name = d.read_string(member)?;
1034 }
1035 Ok(())
1036 })
1037 .unwrap();
1038
1039 assert_eq!(name, "Bob");
1040 }
1041
1042 #[test]
1046 fn colliding_element_names_resolve_to_the_first_member() {
1047 static STATUS: Schema<'static> = Schema::new_member(
1048 shape_id!("ns", "S", "status"),
1049 ShapeType::String,
1050 "status",
1051 0,
1052 );
1053 static STATUS_TEXT: Schema<'static> = Schema::new_member(
1054 shape_id!("ns", "S", "statusText"),
1055 ShapeType::String,
1056 "statusText",
1057 1,
1058 )
1059 .with_xml_name("status");
1060 static OTHER: Schema<'static> =
1061 Schema::new_member(shape_id!("ns", "S", "other"), ShapeType::String, "other", 2);
1062 static S: Schema<'static> = Schema::new_struct(
1063 shape_id!("ns", "S"),
1064 ShapeType::Structure,
1065 &[&STATUS, &STATUS_TEXT, &OTHER],
1066 );
1067
1068 fn read(xml: &[u8]) -> Vec<(usize, String)> {
1069 let mut deser = XmlDeserializer::new(xml, Arc::new(XmlCodecSettings::default()));
1070 let mut seen = Vec::new();
1071 deser
1072 .read_struct(&S, &mut |member, d| {
1073 seen.push((member.member_index().unwrap(), d.read_string(member)?));
1074 Ok(())
1075 })
1076 .unwrap();
1077 seen
1078 }
1079
1080 assert_eq!(
1081 read(b"<S><status>a</status><status>b</status></S>"),
1082 [(0, "a".to_owned()), (0, "b".to_owned())]
1083 );
1084 assert_eq!(
1085 read(b"<S><other>x</other><status>a</status></S>"),
1086 [(2, "x".to_owned()), (0, "a".to_owned())]
1087 );
1088 }
1089
1090 #[test]
1091 fn strict_read_rejects_ill_formed_xml() {
1092 static P_STRING: Schema<'static> =
1093 Schema::new_member(shape_id!("test", "P$s"), ShapeType::String, "s", 0);
1094 static P_LIST: Schema<'static> =
1095 Schema::new_member(shape_id!("test", "P$list"), ShapeType::List, "list", 1);
1096 static P_FLAT: Schema<'static> =
1097 Schema::new_member(shape_id!("test", "P$flat"), ShapeType::List, "flat", 2)
1098 .with_xml_flattened();
1099 static P_MAP: Schema<'static> =
1100 Schema::new_member(shape_id!("test", "P$map"), ShapeType::Map, "map", 3);
1101 static P_SCHEMA: Schema<'static> = Schema::new_struct(
1102 shape_id!("test", "P"),
1103 ShapeType::Structure,
1104 &[&P_STRING, &P_LIST, &P_FLAT, &P_MAP],
1105 );
1106 static MAP_KEY: Schema<'static> =
1107 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1108 static MAP_VALUE: Schema<'static> =
1109 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
1110 static MAP_SCHEMA: Schema<'static> =
1111 Schema::new_map(shape_id!("test", "M"), &MAP_KEY, &MAP_VALUE);
1112
1113 fn read(input: &str, strict: bool) -> Result<(), SerdeError> {
1114 let settings = Arc::new(
1115 XmlCodecSettings::builder()
1116 .enforce_strictness(strict)
1117 .build(),
1118 );
1119 XmlDeserializer::new(input.as_bytes(), settings).read_struct(&P_SCHEMA, &mut |m, d| {
1120 match m.member_name().unwrap() {
1121 "s" => d.read_string(m).map(|_| ()),
1122 "list" | "flat" => d.read_list(m, &mut |d| d.read_string(m).map(|_| ())),
1123 _ => d.read_map(&MAP_SCHEMA, &mut |_, d| d.read_string(m).map(|_| ())),
1124 }
1125 })
1126 }
1127
1128 for ok in [
1129 "<P><s>x</s><list><member>a</member></list><flat>b</flat><flat>c</flat></P>",
1130 "<?xml version=\"1.0\"?><!-- c --><P><s><![CDATA[<x>]]></s></P>\n<!-- trailing -->",
1131 r#"<a:P xmlns:a="u"><a:s>x</a:s><list ><member/></list ></a:P>"#,
1132 "<P><unknown><deep/></unknown><map><entry><key>k</key><value>v</value></entry></map></P>",
1133 "<P/>",
1134 ] {
1135 read(ok, true).unwrap_or_else(|e| panic!("well-formed {ok:?} rejected: {e}"));
1136 }
1137
1138 for bad in [
1139 "<P><map><gntry><key>k</key><value>v</value></entry></map><s>s</s></P>",
1141 "<P><list><member>a</member></l><member>b</member></list></P>",
1142 "<P><flat>a</flatx><flat>b</flat></P>",
1144 "<P><unknown><deep></unknown></P>",
1145 r#"<P xmlns:a="u" xmlns:b="v"><a:s>x</b:s></P>"#,
1147 r#"<P xmlns:a="u"><s>x</a:s></P>"#,
1148 r#"<P xmlns:a="u"><a:s>x</s></P>"#,
1149 "<P><s>x</s>",
1151 "<P><s>x</P>",
1152 "<P><s>x</s></P></P>",
1154 "<P></P><P></P>",
1155 ] {
1156 assert!(read(bad, true).is_err(), "ill-formed {bad:?} accepted");
1157 let _ = read(bad, false);
1159 }
1160 read("<P><s>x</s>", false).expect("lenient read accepts an unclosed root");
1162 }
1163
1164 #[test]
1165 fn strict_roots_only_validate_document_boundary() {
1166 static CHILD: Schema<'static> = Schema::new_struct(
1167 aws_smithy_schema::shape_id!("test", "Child"),
1168 aws_smithy_schema::ShapeType::Structure,
1169 &[],
1170 );
1171 static RENAMED: Schema<'static> = Schema::new_member(
1172 aws_smithy_schema::shape_id!("test", "Root", "child"),
1173 aws_smithy_schema::ShapeType::Structure,
1174 "child",
1175 0,
1176 )
1177 .with_xml_name("Renamed");
1178 static ROOT: Schema<'static> = Schema::new_struct(
1179 aws_smithy_schema::shape_id!("test", "Synthetic"),
1180 aws_smithy_schema::ShapeType::Structure,
1181 &[&RENAMED],
1182 )
1183 .with_original_name("Original")
1184 .with_xml_name("WireRoot");
1185 for strict in [false, true] {
1186 let settings = Arc::new(
1187 XmlCodecSettings::builder()
1188 .enforce_strictness(strict)
1189 .build(),
1190 );
1191 for (input, matches) in [
1192 (b"<WireRoot><Renamed/></WireRoot>".as_slice(), true),
1193 (b"<Wrong><Renamed/></Wrong>", false),
1194 ] {
1195 let mut visited = false;
1196 let result = XmlDeserializer::new(input, settings.clone()).read_struct(
1197 &ROOT,
1198 &mut |_, d| {
1199 visited = true;
1200 d.read_struct(&CHILD, &mut |_, _| Ok(()))
1201 },
1202 );
1203 assert_eq!(result.is_ok(), !strict || matches);
1204 assert_eq!(visited, !strict || matches);
1205 }
1206 }
1207 }
1208
1209 #[test]
1210 fn read_struct_resolves_xml_name() {
1211 let xml = b"<Person><Nickname>Ally</Nickname></Person>";
1212 let settings = Arc::new(XmlCodecSettings::default());
1213 let mut deser = XmlDeserializer::new(xml, settings);
1214
1215 let mut nick = String::new();
1216 deser
1217 .read_struct(&PERSON_SCHEMA, &mut |member, d| {
1218 if member.member_name() == Some("nick") {
1219 nick = d.read_string(member)?;
1220 }
1221 Ok(())
1222 })
1223 .unwrap();
1224
1225 assert_eq!(nick, "Ally");
1226 }
1227
1228 static ATTR_MEMBER: Schema<'static> =
1231 Schema::new_member(shape_id!("test", "X$id"), ShapeType::String, "id", 0)
1232 .with_xml_attribute();
1233 static ELEM_MEMBER: Schema<'static> =
1234 Schema::new_member(shape_id!("test", "X$name"), ShapeType::String, "name", 1);
1235
1236 static X_SCHEMA: Schema<'static> = Schema::new_struct(
1237 shape_id!("test", "X"),
1238 ShapeType::Structure,
1239 &[&ATTR_MEMBER, &ELEM_MEMBER],
1240 );
1241
1242 #[test]
1243 fn read_struct_dispatches_attributes() {
1244 let xml = b"<X id=\"42\"><name>hello</name></X>";
1245 let settings = Arc::new(XmlCodecSettings::default());
1246 let mut deser = XmlDeserializer::new(xml, settings);
1247
1248 let mut id = String::new();
1249 let mut name = String::new();
1250 deser
1251 .read_struct(&X_SCHEMA, &mut |member, d| {
1252 match member.member_name().unwrap() {
1253 "id" => id = d.read_string(member)?,
1254 "name" => name = d.read_string(member)?,
1255 _ => {}
1256 }
1257 Ok(())
1258 })
1259 .unwrap();
1260
1261 assert_eq!(id, "42");
1262 assert_eq!(name, "hello");
1263 }
1264
1265 #[test]
1268 fn read_list_wrapped() {
1269 let xml = b"<items><member>a</member><member>b</member></items>";
1270 let settings = Arc::new(XmlCodecSettings::default());
1271 let mut deser = XmlDeserializer::new(xml, settings);
1272
1273 static LIST_MEMBER: Schema<'static> = Schema::new_member(
1274 shape_id!("test", "L$member"),
1275 ShapeType::String,
1276 "member",
1277 0,
1278 );
1279 static LIST_SCHEMA: Schema<'static> =
1280 Schema::new_list(shape_id!("test", "L"), &LIST_MEMBER);
1281
1282 let mut items = Vec::new();
1283 deser
1284 .read_list(&LIST_SCHEMA, &mut |d| {
1285 items.push(d.read_string(&LIST_MEMBER)?);
1286 Ok(())
1287 })
1288 .unwrap();
1289
1290 assert_eq!(items, vec!["a", "b"]);
1291 }
1292
1293 #[test]
1294 fn read_map_wrapped() {
1295 let xml = b"<myMap><entry><key>k1</key><value>v1</value></entry><entry><key>k2</key><value>v2</value></entry></myMap>";
1296 let settings = Arc::new(XmlCodecSettings::default());
1297 let mut deser = XmlDeserializer::new(xml, settings);
1298
1299 static MAP_KEY: Schema<'static> =
1300 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1301 static MAP_VALUE: Schema<'static> =
1302 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 0);
1303 static MAP_SCHEMA: Schema<'static> =
1304 Schema::new_map(shape_id!("test", "M"), &MAP_KEY, &MAP_VALUE);
1305
1306 let mut entries = Vec::new();
1307 deser
1308 .read_map(&MAP_SCHEMA, &mut |k, d| {
1309 entries.push((k, d.read_string(&MAP_VALUE)?));
1310 Ok(())
1311 })
1312 .unwrap();
1313
1314 assert_eq!(
1315 entries,
1316 vec![
1317 ("k1".to_owned(), "v1".to_owned()),
1318 ("k2".to_owned(), "v2".to_owned())
1319 ]
1320 );
1321 }
1322
1323 #[test]
1324 fn read_map_with_renamed_key_value() {
1325 let xml = b"<m><entry><Attribute>a</Attribute><Setting>s</Setting></entry></m>";
1326 let settings = Arc::new(XmlCodecSettings::default());
1327 let mut deser = XmlDeserializer::new(xml, settings);
1328
1329 static MAP_KEY: Schema<'static> =
1330 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0)
1331 .with_xml_name("Attribute");
1332 static MAP_VALUE: Schema<'static> =
1333 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 0)
1334 .with_xml_name("Setting");
1335 static MAP_SCHEMA: Schema<'static> =
1336 Schema::new_map(shape_id!("test", "M"), &MAP_KEY, &MAP_VALUE);
1337
1338 let mut entries = Vec::new();
1339 deser
1340 .read_map(&MAP_SCHEMA, &mut |k, d| {
1341 entries.push((k, d.read_string(&MAP_VALUE)?));
1342 Ok(())
1343 })
1344 .unwrap();
1345
1346 assert_eq!(entries, vec![("a".to_owned(), "s".to_owned())]);
1347 }
1348
1349 #[test]
1352 fn read_struct_flattened_list() {
1353 let xml = b"<S><name>hi</name><item>a</item><item>b</item></S>";
1355 let settings = Arc::new(XmlCodecSettings::default());
1356 let mut deser = XmlDeserializer::new(xml, settings);
1357
1358 static S_NAME: Schema<'static> =
1359 Schema::new_member(shape_id!("test", "S$name"), ShapeType::String, "name", 0);
1360 static S_ITEMS: Schema<'static> =
1361 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 1)
1362 .with_xml_flattened()
1363 .with_xml_name("item");
1364 static S_SCHEMA: Schema<'static> = Schema::new_struct(
1365 shape_id!("test", "S"),
1366 ShapeType::Structure,
1367 &[&S_NAME, &S_ITEMS],
1368 );
1369
1370 let mut name = String::new();
1371 let mut items = Vec::new();
1372 deser
1373 .read_struct(&S_SCHEMA, &mut |member, d| {
1374 match member.member_name().unwrap() {
1375 "name" => name = d.read_string(member)?,
1376 "items" => d.read_list(member, &mut |d| {
1377 items.push(d.read_string(member)?);
1378 Ok(())
1379 })?,
1380 _ => {}
1381 }
1382 Ok(())
1383 })
1384 .unwrap();
1385
1386 assert_eq!(name, "hi");
1387 assert_eq!(items, vec!["a", "b"]);
1388 }
1389
1390 #[test]
1396 fn read_struct_ignores_markup_in_comments_cdata_pi_attrs() {
1397 static S_ITEMS: Schema<'static> =
1398 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0)
1399 .with_xml_flattened()
1400 .with_xml_name("item");
1401 static S_PEOPLE: Schema<'static> =
1402 Schema::new_member(shape_id!("test", "S$people"), ShapeType::List, "people", 1);
1403 static S_MAP: Schema<'static> =
1404 Schema::new_member(shape_id!("test", "S$m"), ShapeType::Map, "m", 2);
1405 static S_SCHEMA: Schema<'static> = Schema::new_struct(
1406 shape_id!("test", "S"),
1407 ShapeType::Structure,
1408 &[&S_ITEMS, &S_PEOPLE, &S_MAP],
1409 );
1410 static PEOPLE_MEMBER: Schema<'static> = Schema::new_member(
1411 shape_id!("test", "People$member"),
1412 ShapeType::Structure,
1413 "member",
1414 0,
1415 );
1416 static PEOPLE_SCHEMA: Schema<'static> =
1417 Schema::new_list(shape_id!("test", "People"), &PEOPLE_MEMBER);
1418 static MAP_KEY: Schema<'static> =
1419 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1420 static MAP_VALUE: Schema<'static> = Schema::new_member(
1421 shape_id!("test", "M$value"),
1422 ShapeType::Structure,
1423 "value",
1424 1,
1425 );
1426 static MAP_SCHEMA: Schema<'static> =
1427 Schema::new_map(shape_id!("test", "M"), &MAP_KEY, &MAP_VALUE);
1428
1429 let xml = concat!(
1430 "<S>",
1431 "<item><!--><item>-->a</item>",
1432 "<item><![CDATA[><item>]]></item>",
1433 "<item><?pi <item>?>c</item>",
1434 r#"<item x="/>">d</item>"#,
1435 "<people>",
1436 "<member><!--><member>--><name>p1</name></member>",
1437 r#"<member x="/>"><![CDATA[<member>]]><name>p2</name></member>"#,
1438 "</people>",
1439 "<m><entry><key>k</key><value><!--><value>--><name>v</name></value></entry></m>",
1440 "</S>",
1441 );
1442 let mut deser = XmlDeserializer::new(xml.as_bytes(), Arc::new(XmlCodecSettings::default()));
1443
1444 fn read_name(d: &mut dyn ShapeDeserializer) -> Result<String, SerdeError> {
1445 let mut name = String::new();
1446 d.read_struct(&PERSON_SCHEMA, &mut |member, d| {
1447 if member.member_name() == Some("name") {
1448 name = d.read_string(member)?;
1449 }
1450 Ok(())
1451 })?;
1452 Ok(name)
1453 }
1454
1455 let (mut items, mut people, mut map) = (Vec::new(), Vec::new(), Vec::new());
1456 deser
1457 .read_struct(&S_SCHEMA, &mut |member, d| {
1458 match member.member_name().unwrap() {
1459 "items" => d.read_list(member, &mut |d| {
1460 items.push(d.read_string(member)?);
1461 Ok(())
1462 })?,
1463 "people" => d.read_list(&PEOPLE_SCHEMA, &mut |d| {
1464 people.push(read_name(d)?);
1465 Ok(())
1466 })?,
1467 "m" => d.read_map(&MAP_SCHEMA, &mut |k, d| {
1468 map.push((k, read_name(d)?));
1469 Ok(())
1470 })?,
1471 _ => {}
1472 }
1473 Ok(())
1474 })
1475 .unwrap();
1476
1477 assert_eq!(items, vec!["a", "", "c", "d"]);
1478 assert_eq!(people, vec!["p1", "p2"]);
1479 assert_eq!(map, vec![("k".to_owned(), "v".to_owned())]);
1480 }
1481
1482 #[test]
1483 fn read_struct_flattened_list_intermixed() {
1484 let xml = b"<S><item>x</item><name>n</name><item>y</item></S>";
1486 let settings = Arc::new(XmlCodecSettings::default());
1487 let mut deser = XmlDeserializer::new(xml, settings);
1488
1489 static S_NAME: Schema<'static> =
1490 Schema::new_member(shape_id!("test", "S$name"), ShapeType::String, "name", 0);
1491 static S_ITEMS: Schema<'static> =
1492 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 1)
1493 .with_xml_flattened()
1494 .with_xml_name("item");
1495 static S_SCHEMA: Schema<'static> = Schema::new_struct(
1496 shape_id!("test", "S"),
1497 ShapeType::Structure,
1498 &[&S_NAME, &S_ITEMS],
1499 );
1500
1501 let mut name = String::new();
1502 let mut items = Vec::new();
1503 deser
1504 .read_struct(&S_SCHEMA, &mut |member, d| {
1505 match member.member_name().unwrap() {
1506 "name" => name = d.read_string(member)?,
1507 "items" => d.read_list(member, &mut |d| {
1508 items.push(d.read_string(member)?);
1509 Ok(())
1510 })?,
1511 _ => {}
1512 }
1513 Ok(())
1514 })
1515 .unwrap();
1516
1517 assert_eq!(name, "n");
1518 assert_eq!(items, vec!["x", "y"]);
1519 }
1520
1521 #[test]
1522 fn read_struct_flattened_map() {
1523 let xml = b"<S><attr><key>a</key><value>1</value></attr><name>n</name>\
1526 <entry><key>x</key><value>9</value></entry>\
1527 <attr><key>b</key><value>2</value></attr></S>";
1528
1529 static MAP_KEY: Schema<'static> =
1530 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1531 static MAP_VALUE: Schema<'static> =
1532 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
1533 static S_NAME: Schema<'static> =
1534 Schema::new_member(shape_id!("test", "S$name"), ShapeType::String, "name", 0);
1535 static S_ATTRS: Schema<'static> =
1536 Schema::new_member(shape_id!("test", "S$attrs"), ShapeType::Map, "attrs", 1)
1537 .with_map_members(&MAP_KEY, &MAP_VALUE)
1538 .with_xml_flattened()
1539 .with_xml_name("attr");
1540 static S_SCHEMA: Schema<'static> = Schema::new_struct(
1541 shape_id!("test", "S"),
1542 ShapeType::Structure,
1543 &[&S_NAME, &S_ATTRS],
1544 );
1545
1546 for (helper, check_names) in [(false, false), (true, false), (false, true), (true, true)] {
1547 let settings = XmlCodecSettings::builder()
1548 .strict_collection_element_names(check_names)
1549 .build();
1550 let mut deser = XmlDeserializer::new(xml, Arc::new(settings));
1551 let mut attrs = Vec::new();
1552 deser
1553 .read_struct(&S_SCHEMA, &mut |member, d| {
1554 if member.member_name() == Some("attrs") {
1555 if helper {
1556 attrs.extend(d.read_string_string_map(member)?);
1557 } else {
1558 d.read_map(member, &mut |k, d| {
1559 attrs.push((k, d.read_string(&MAP_VALUE)?));
1560 Ok(())
1561 })?;
1562 }
1563 }
1564 Ok(())
1565 })
1566 .unwrap();
1567 attrs.sort();
1568 assert_eq!(
1569 attrs,
1570 vec![
1571 ("a".to_owned(), "1".to_owned()),
1572 ("b".to_owned(), "2".to_owned())
1573 ]
1574 );
1575 }
1576 }
1577
1578 #[test]
1581 fn read_scalars() {
1582 let settings = Arc::new(XmlCodecSettings::default());
1583
1584 let mut d = XmlDeserializer::from_text(Cow::Borrowed("true"), settings.clone());
1585 assert!(d.read_boolean(&STRING_MEMBER).unwrap());
1586
1587 let mut d = XmlDeserializer::from_text(Cow::Borrowed("-42"), settings.clone());
1588 assert_eq!(d.read_integer(&STRING_MEMBER).unwrap(), -42);
1589
1590 let mut d = XmlDeserializer::from_text(Cow::Borrowed("NaN"), settings.clone());
1591 assert!(d.read_float(&STRING_MEMBER).unwrap().is_nan());
1592
1593 let mut d = XmlDeserializer::from_text(Cow::Borrowed("Infinity"), settings.clone());
1594 assert_eq!(d.read_double(&STRING_MEMBER).unwrap(), f64::INFINITY);
1595
1596 let mut d = XmlDeserializer::from_text(Cow::Borrowed("aGVsbG8="), settings.clone());
1597 assert_eq!(d.read_blob(&STRING_MEMBER).unwrap().as_ref(), b"hello");
1598
1599 let mut d =
1600 XmlDeserializer::from_text(Cow::Borrowed("2023-04-01T12:00:00Z"), settings.clone());
1601 let ts = d.read_timestamp(&STRING_MEMBER).unwrap();
1602 assert_eq!(ts.secs(), 1680350400);
1603 }
1604
1605 #[test]
1606 fn read_document_returns_error() {
1607 let settings = Arc::new(XmlCodecSettings::default());
1608 let mut deser = XmlDeserializer::from_text(Cow::Borrowed("x"), settings);
1609 assert_eq!(
1610 deser.read_document(&STRING_MEMBER).unwrap_err().to_string(),
1611 "document types are not supported by REST XML"
1612 );
1613 }
1614
1615 #[test]
1625 fn read_struct_empty_body_errors() {
1626 let settings = Arc::new(XmlCodecSettings::default());
1627 let mut deser = XmlDeserializer::new(b"", settings);
1628 let err = deser
1629 .read_struct(&PERSON_SCHEMA, &mut |_member, _d| Ok(()))
1630 .expect_err("empty body must be rejected by read_struct");
1631 let _ = format!("{err}");
1632 }
1633
1634 #[test]
1635 fn read_list_empty_body_errors() {
1636 let settings = Arc::new(XmlCodecSettings::default());
1637 let mut deser = XmlDeserializer::new(b"", settings);
1638 deser
1639 .read_list(&PERSON_SCHEMA, &mut |_d| Ok(()))
1640 .expect_err("empty body must be rejected by read_list");
1641 }
1642
1643 #[test]
1644 fn read_map_empty_body_errors() {
1645 let settings = Arc::new(XmlCodecSettings::default());
1646 let mut deser = XmlDeserializer::new(b"", settings);
1647 deser
1648 .read_map(&PERSON_SCHEMA, &mut |_k, _d| Ok(()))
1649 .expect_err("empty body must be rejected by read_map");
1650 }
1651
1652 fn settings_with_max_depth(n: u32) -> Arc<XmlCodecSettings> {
1658 Arc::new(XmlCodecSettings::builder().max_depth(n).build())
1659 }
1660
1661 fn nested_struct_xml(depth: u32) -> Vec<u8> {
1663 let mut s = String::new();
1664 for _ in 0..depth {
1665 s.push_str("<r>");
1666 }
1667 s.push('v');
1668 for _ in 0..depth {
1669 s.push_str("</r>");
1670 }
1671 s.into_bytes()
1672 }
1673
1674 #[test]
1675 fn read_struct_rejects_overdeep_payloads() {
1676 static R_MEMBER_SELF: Schema<'static> =
1680 Schema::new_member(shape_id!("test", "R$r"), ShapeType::Structure, "r", 0);
1681 static R_SCHEMA: Schema<'static> = Schema::new_struct(
1682 shape_id!("test", "R"),
1683 ShapeType::Structure,
1684 &[&R_MEMBER_SELF],
1685 );
1686
1687 let max = 4;
1689 let xml = nested_struct_xml(max + 2);
1690 let mut deser = XmlDeserializer::new(&xml, settings_with_max_depth(max));
1691
1692 fn consume(_m: &Schema<'_>, d: &mut dyn ShapeDeserializer) -> Result<(), SerdeError> {
1694 d.read_struct(&R_SCHEMA, &mut consume)
1695 }
1696 let err = deser
1697 .read_struct(&R_SCHEMA, &mut consume)
1698 .expect_err("must reject payload exceeding max_depth");
1699 assert!(
1700 format!("{err}").contains("maximum nesting depth exceeded"),
1701 "expected depth-exceeded error, got: {err}"
1702 );
1703 }
1704
1705 #[test]
1706 fn read_struct_accepts_payloads_up_to_max_depth() {
1707 static R_MEMBER_SELF: Schema<'static> =
1712 Schema::new_member(shape_id!("test", "R$r"), ShapeType::Structure, "r", 0);
1713 static R_SCHEMA: Schema<'static> = Schema::new_struct(
1714 shape_id!("test", "R"),
1715 ShapeType::Structure,
1716 &[&R_MEMBER_SELF],
1717 );
1718
1719 let max = 4;
1723 let xml = nested_struct_xml(max);
1724 let mut deser = XmlDeserializer::new(&xml, settings_with_max_depth(max));
1725
1726 let mut depth_seen = 0u32;
1727 fn consume(
1728 _m: &Schema<'_>,
1729 d: &mut dyn ShapeDeserializer,
1730 depth_seen: &mut u32,
1731 ) -> Result<(), SerdeError> {
1732 *depth_seen += 1;
1733 d.read_struct(&R_SCHEMA, &mut |m, d2| consume(m, d2, depth_seen))
1734 }
1735
1736 deser
1737 .read_struct(&R_SCHEMA, &mut |m, d| consume(m, d, &mut depth_seen))
1738 .expect("payload at exactly max_depth must succeed");
1739 }
1740
1741 #[test]
1742 fn read_list_rejects_overdeep_payloads() {
1743 static L_MEMBER: Schema<'static> =
1745 Schema::new_member(shape_id!("test", "L$member"), ShapeType::List, "member", 0);
1746 static L_SCHEMA: Schema<'static> = Schema::new_list(shape_id!("test", "L"), &L_MEMBER);
1747
1748 let max = 3;
1749 let xml = b"<l><l><l><l><l/></l></l></l></l>";
1751 let mut deser = XmlDeserializer::new(xml, settings_with_max_depth(max));
1752
1753 fn consume(d: &mut dyn ShapeDeserializer) -> Result<(), SerdeError> {
1754 d.read_list(&L_SCHEMA, &mut consume)
1755 }
1756 let err = deser
1757 .read_list(&L_SCHEMA, &mut consume)
1758 .expect_err("nested-list payload exceeding max_depth must error");
1759 assert!(
1760 format!("{err}").contains("maximum nesting depth exceeded"),
1761 "expected depth-exceeded error, got: {err}"
1762 );
1763 }
1764
1765 #[test]
1766 fn depth_resets_between_sibling_reads() {
1767 static R_MEMBER_SELF: Schema<'static> =
1770 Schema::new_member(shape_id!("test", "R$r"), ShapeType::Structure, "r", 0);
1771 static R_SCHEMA: Schema<'static> = Schema::new_struct(
1772 shape_id!("test", "R"),
1773 ShapeType::Structure,
1774 &[&R_MEMBER_SELF],
1775 );
1776
1777 let max = 4;
1778 let xml = nested_struct_xml(2);
1779 let mut deser = XmlDeserializer::new(&xml, settings_with_max_depth(max));
1780
1781 deser
1783 .read_struct(&R_SCHEMA, &mut |_m, d| {
1784 d.read_struct(&R_SCHEMA, &mut |_, _| Ok(()))
1785 })
1786 .expect("first read at depth=2 must succeed");
1787
1788 deser
1791 .read_struct(&R_SCHEMA, &mut |_m, d| {
1792 d.read_struct(&R_SCHEMA, &mut |_, _| Ok(()))
1793 })
1794 .expect("sibling read on the same deserializer must succeed");
1795 }
1796
1797 #[test]
1798 fn read_struct_rejects_overdeep_payloads_through_flattened_member() {
1799 static NODE_KIDS: Schema<'static> =
1811 Schema::new_member(shape_id!("test", "Node$kids"), ShapeType::List, "kids", 0)
1812 .with_xml_flattened()
1813 .with_xml_name("kids");
1814 static NODE_SCHEMA: Schema<'static> = Schema::new_struct(
1815 shape_id!("test", "Node"),
1816 ShapeType::Structure,
1817 &[&NODE_KIDS],
1818 );
1819
1820 let max = 4;
1825 let depth = 50usize;
1826 let mut xml = Vec::new();
1827 xml.extend_from_slice(b"<Node>");
1828 for _ in 0..depth {
1829 xml.extend_from_slice(b"<kids>");
1830 }
1831 for _ in 0..depth {
1832 xml.extend_from_slice(b"</kids>");
1833 }
1834 xml.extend_from_slice(b"</Node>");
1835
1836 let mut deser = XmlDeserializer::new(&xml, settings_with_max_depth(max));
1837
1838 fn consume(_m: &Schema<'_>, d: &mut dyn ShapeDeserializer) -> Result<(), SerdeError> {
1841 d.read_struct(&NODE_SCHEMA, &mut |member, d| {
1842 d.read_list(member, &mut |d| consume(&NODE_SCHEMA, d))
1843 })
1844 }
1845
1846 let err = consume(&NODE_SCHEMA, &mut deser)
1847 .expect_err("recursion through a flattened member must be depth-limited");
1848 assert!(
1849 format!("{err}").contains("maximum nesting depth exceeded"),
1850 "expected depth-exceeded error, got: {err}"
1851 );
1852 }
1853
1854 #[test]
1855 fn depth_resets_after_consumer_error() {
1856 static L_MEMBER: Schema<'static> = Schema::new_member(
1869 shape_id!("test", "L$member"),
1870 ShapeType::String,
1871 "member",
1872 0,
1873 );
1874 static L_SCHEMA: Schema<'static> = Schema::new_list(shape_id!("test", "L"), &L_MEMBER);
1875
1876 let max = 2;
1882 let xml = b"<l><member>a</member><member>b</member></l>";
1883 let mut deser = XmlDeserializer::new(xml, settings_with_max_depth(max));
1884
1885 let mut force_err = |_: &mut dyn ShapeDeserializer| -> Result<(), SerdeError> {
1887 Err(SerdeError::custom("forced"))
1888 };
1889 deser
1890 .read_list(&L_SCHEMA, &mut force_err)
1891 .expect_err("forced consumer error must propagate");
1892
1893 for i in 0..(max as usize + 5) {
1897 deser
1898 .read_list(&L_SCHEMA, &mut force_err)
1899 .expect_err(&format!("forced consumer error must propagate (iter {i})"));
1900 }
1901
1902 let mut count = 0usize;
1905 deser
1906 .read_list(&L_SCHEMA, &mut |d| {
1907 count += 1;
1908 d.read_string(&L_MEMBER).map(|_| ())
1909 })
1910 .expect("subsequent successful read must not be poisoned by prior errors");
1911 assert_eq!(count, 2);
1912 }
1913
1914 #[test]
1915 fn read_struct_unwrapped_output_with_prolog() {
1916 static MEMBER: Schema<'static> = Schema::new_member(
1930 shape_id!("test", "U$location"),
1931 ShapeType::String,
1932 "LocationConstraint",
1933 0,
1934 );
1935 static SCHEMA: Schema<'static> =
1936 Schema::new_struct(shape_id!("test", "U"), ShapeType::Structure, &[&MEMBER])
1937 .with_xml_unwrapped_output();
1938
1939 let xml = b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<LocationConstraint>us-west-2</LocationConstraint>";
1940 let mut deser = XmlDeserializer::new(xml, Arc::new(XmlCodecSettings::default()));
1941
1942 let mut got = String::new();
1943 deser
1944 .read_struct(&SCHEMA, &mut |member, d| {
1945 got = d.read_string(member)?;
1946 Ok(())
1947 })
1948 .expect("unwrapped output must deserialize through prolog");
1949 assert_eq!(got, "us-west-2");
1950 }
1951
1952 #[test]
1965 fn element_slicing_handles_multibyte_utf8() {
1966 static KEY_MEMBER: Schema<'static> =
1971 Schema::new_member(shape_id!("test", "Wrapper$k"), ShapeType::Map, "entries", 0);
1972 static MAP_SCHEMA: Schema<'static> = Schema::new_map(
1973 shape_id!("test", "MyMap"),
1974 &aws_smithy_schema::prelude::STRING,
1975 &aws_smithy_schema::prelude::STRING,
1976 );
1977 static WRAPPER: Schema<'static> = Schema::new_struct(
1978 shape_id!("test", "Wrapper"),
1979 ShapeType::Structure,
1980 &[&KEY_MEMBER],
1981 );
1982 let _ = MAP_SCHEMA; let xml =
1985 "<Wrapper><entries><entry><key>Б</key><value></value></entry></entries></Wrapper>";
1986
1987 let settings = Arc::new(XmlCodecSettings::default());
1988 let mut deser = XmlDeserializer::new(xml.as_bytes(), settings);
1989
1990 let mut entries = Vec::new();
1991 deser
1992 .read_struct(&WRAPPER, &mut |member, d| {
1993 d.read_map(member, &mut |k, d| {
1994 entries.push((k, d.read_string(&aws_smithy_schema::prelude::STRING)?));
1995 Ok(())
1996 })
1997 })
1998 .expect("must not panic on multi-byte UTF-8 inside map elements");
1999
2000 assert_eq!(entries, vec![("Б".to_owned(), String::new())]);
2001 }
2002
2003 fn child_slices(input: &[u8]) -> Vec<&[u8]> {
2006 let mut doc = Document::try_from(input).unwrap();
2007 let mut root = doc.root_element().unwrap();
2008 let mut out = Vec::new();
2009 while let Some(child) = root.next_tag() {
2010 let start = XmlDeserializer::element_start(input, child.start_el().local());
2011 out.push(&input[start..child.end_offset()]);
2012 }
2013 out
2014 }
2015
2016 #[test]
2019 fn element_slices_prefixed_and_whitespace() {
2020 let input = br#"<Root><a:flatList xmlns:a="u">x</a:flatList><a:flatList xmlns:a="u">y</a:flatList></Root>"#;
2021 assert_eq!(
2022 child_slices(input),
2023 vec![
2024 &br#"<a:flatList xmlns:a="u">x</a:flatList>"#[..],
2025 &br#"<a:flatList xmlns:a="u">y</a:flatList>"#[..],
2026 ],
2027 );
2028 let ws = b"<Root><flatList >x</flatList ><flatList>y</flatList></Root>";
2029 assert_eq!(
2030 child_slices(ws),
2031 vec![
2032 &b"<flatList >x</flatList >"[..],
2033 &b"<flatList>y</flatList>"[..]
2034 ],
2035 );
2036 let empty = b"<Root><a/><b x=\"1\" /></Root>";
2037 assert_eq!(
2038 child_slices(empty),
2039 vec![&b"<a/>"[..], &b"<b x=\"1\" />"[..]]
2040 );
2041 }
2042
2043 #[test]
2049 fn element_slices_ignore_markup_in_comments_cdata_pi_attrs() {
2050 for item in [
2051 &b"<flatList><!--><flatList>--></flatList>"[..],
2052 b"<flatList><![CDATA[><flatList>]]></flatList>",
2053 b"<flatList><?pi <flatList>?>x</flatList>",
2054 b"<flatList a=\"/>\">x</flatList>",
2055 b"<flatList><!-- </flatList> -->x</flatList>",
2056 ] {
2057 let mut input = b"<Root>".to_vec();
2058 for _ in 0..3 {
2059 input.extend_from_slice(item);
2060 }
2061 input.extend_from_slice(b"</Root>");
2062 assert_eq!(
2063 child_slices(&input),
2064 vec![item; 3],
2065 "{}",
2066 String::from_utf8_lossy(item)
2067 );
2068 }
2069 }
2070
2071 #[test]
2072 fn find_depth2_by_predicate_wrapped() {
2073 let xml = b"<Resp><FooResult><A>1</A></FooResult><Metadata/></Resp>";
2074 let got = find_depth2_element_slice_by(xml, |n| n.ends_with("Result"));
2075 assert_eq!(got, Some(&b"<FooResult><A>1</A></FooResult>"[..]));
2076 }
2077
2078 #[test]
2079 fn find_depth2_by_predicate_self_closing() {
2080 let xml = b"<Resp><FooResult/><Metadata><Id>r</Id></Metadata></Resp>";
2083 let got = find_depth2_element_slice_by(xml, |n| n.ends_with("Result"));
2084 assert_eq!(got, Some(&b"<FooResult/>"[..]));
2085 }
2086
2087 #[test]
2088 fn find_depth2_by_predicate_root_match() {
2089 let xml = b"<Error><Code>Boom</Code></Error>";
2091 let got = find_depth2_element_slice_by(xml, |n| n == "Error");
2092 assert_eq!(got, Some(&xml[..]));
2093 }
2094
2095 #[test]
2096 fn find_depth2_by_predicate_no_match() {
2097 let xml = b"<Resp><Metadata/></Resp>";
2098 assert_eq!(find_depth2_element_slice_by(xml, |n| n == "Error"), None);
2099 }
2100
2101 #[test]
2102 fn find_depth2_by_predicate_invalid_xml() {
2103 assert_eq!(find_depth2_element_slice_by(b"not xml", |_| true), None);
2104 }
2105
2106 #[test]
2114 fn read_string_list_helper() {
2115 let xml = b"<items><member>a</member><member>b</member><member></member></items>";
2116 let settings = Arc::new(XmlCodecSettings::default());
2117 let mut deser = XmlDeserializer::new(xml, settings);
2118
2119 static LIST_MEMBER: Schema<'static> = Schema::new_member(
2120 shape_id!("test", "L$member"),
2121 ShapeType::String,
2122 "member",
2123 0,
2124 );
2125 static LIST_SCHEMA: Schema<'static> =
2126 Schema::new_list(shape_id!("test", "L"), &LIST_MEMBER);
2127
2128 let out = deser.read_string_list(&LIST_SCHEMA).unwrap();
2129 assert_eq!(out, vec!["a".to_owned(), "b".to_owned(), String::new()]);
2130 }
2131
2132 #[test]
2133 fn read_string_list_helper_renamed_member_name() {
2134 let xml = b"<items><Item>x</Item><Item>y</Item></items>";
2139 let settings = Arc::new(XmlCodecSettings::default());
2140 let mut deser = XmlDeserializer::new(xml, settings);
2141
2142 static LIST_MEMBER: Schema<'static> = Schema::new_member(
2143 shape_id!("test", "L$member"),
2144 ShapeType::String,
2145 "member",
2146 0,
2147 );
2148 static LIST_SCHEMA: Schema<'static> =
2149 Schema::new_list(shape_id!("test", "L"), &LIST_MEMBER);
2150
2151 let out = deser.read_string_list(&LIST_SCHEMA).unwrap();
2152 assert_eq!(out, vec!["x".to_owned(), "y".to_owned()]);
2153 }
2154
2155 fn element_name_settings(check_names: bool) -> Arc<XmlCodecSettings> {
2159 Arc::new(
2160 XmlCodecSettings::builder()
2161 .enforce_strictness(!check_names)
2162 .strict_collection_element_names(check_names)
2163 .build(),
2164 )
2165 }
2166
2167 #[test]
2172 fn element_name_check_skips_list_children_not_named_as_the_member() {
2173 static STRING_MEMBER: Schema<'static> = Schema::new_member(
2174 shape_id!("test", "L$member"),
2175 ShapeType::String,
2176 "member",
2177 0,
2178 );
2179 static STRING_LIST: Schema<'static> =
2180 Schema::new_list(shape_id!("test", "L"), &STRING_MEMBER);
2181 static STRUCT_MEMBER: Schema<'static> =
2183 Schema::new_member(shape_id!("test", "S$tags"), ShapeType::List, "tags", 0)
2184 .with_list_member(&STRING_MEMBER);
2185 static RENAMED_MEMBER: Schema<'static> = Schema::new_member(
2186 shape_id!("test", "R$member"),
2187 ShapeType::String,
2188 "member",
2189 0,
2190 )
2191 .with_xml_name("Item");
2192 static RENAMED_LIST: Schema<'static> =
2193 Schema::new_list(shape_id!("test", "R"), &RENAMED_MEMBER);
2194 static BLOB_MEMBER: Schema<'static> =
2195 Schema::new_member(shape_id!("test", "B$member"), ShapeType::Blob, "member", 0);
2196 static BLOB_LIST: Schema<'static> = Schema::new_list(shape_id!("test", "B"), &BLOB_MEMBER);
2197 static INT_MEMBER: Schema<'static> = Schema::new_member(
2198 shape_id!("test", "I$member"),
2199 ShapeType::Integer,
2200 "member",
2201 0,
2202 );
2203 static INT_LIST: Schema<'static> = Schema::new_list(shape_id!("test", "I"), &INT_MEMBER);
2204 static LONG_MEMBER: Schema<'static> =
2205 Schema::new_member(shape_id!("test", "Lo$member"), ShapeType::Long, "member", 0);
2206 static LONG_LIST: Schema<'static> = Schema::new_list(shape_id!("test", "Lo"), &LONG_MEMBER);
2207
2208 fn deser(xml: &'static str, check_names: bool) -> XmlDeserializer<'static> {
2209 XmlDeserializer::new(xml.as_bytes(), element_name_settings(check_names))
2210 }
2211 fn read_list(xml: &'static str, check_names: bool, schema: &Schema<'_>) -> Vec<String> {
2212 let mut items = Vec::new();
2213 deser(xml, check_names)
2214 .read_list(schema, &mut |d| {
2215 items.push(d.read_string(&STRING_MEMBER)?);
2216 Ok(())
2217 })
2218 .unwrap();
2219 items
2220 }
2221
2222 let strings =
2223 "<tags><item>a</item><member>b</member><Member>c</Member><p:member>d</p:member></tags>";
2224 for schema in [&STRING_LIST, &STRUCT_MEMBER] {
2225 assert_eq!(
2226 deser(strings, true).read_string_list(schema).unwrap(),
2227 vec!["b", "d"]
2228 );
2229 assert_eq!(read_list(strings, true, schema), vec!["b", "d"]);
2230 assert_eq!(
2231 deser(strings, false).read_string_list(schema).unwrap(),
2232 vec!["a", "b", "c", "d"]
2233 );
2234 assert_eq!(read_list(strings, false, schema), vec!["a", "b", "c", "d"]);
2235 }
2236
2237 let renamed = "<l><Item>x</Item><member>skipped</member><Item>y</Item></l>";
2238 assert_eq!(
2239 deser(renamed, true)
2240 .read_string_list(&RENAMED_LIST)
2241 .unwrap(),
2242 vec!["x", "y"]
2243 );
2244 assert_eq!(
2245 deser(renamed, false)
2246 .read_string_list(&RENAMED_LIST)
2247 .unwrap(),
2248 vec!["x", "skipped", "y"]
2249 );
2250
2251 let blobs = deser("<l><x>!!!</x><member>aGVsbG8=</member></l>", true)
2253 .read_blob_list(&BLOB_LIST)
2254 .unwrap();
2255 assert_eq!(blobs, vec![Blob::new("hello")]);
2256 assert_eq!(
2257 deser("<l><x>nan</x><member>7</member></l>", true)
2258 .read_integer_list(&INT_LIST)
2259 .unwrap(),
2260 vec![7]
2261 );
2262 assert_eq!(
2263 deser("<l><x><deep/></x><member>-9</member></l>", true)
2264 .read_long_list(&LONG_LIST)
2265 .unwrap(),
2266 vec![-9]
2267 );
2268 }
2269
2270 #[test]
2274 fn element_name_check_without_a_member_schema_reads_every_child() {
2275 let xml = b"<l><a>1</a><b>2</b></l>";
2276 let mut deser = XmlDeserializer::new(xml, element_name_settings(true));
2277 let mut items = Vec::new();
2278 deser
2279 .read_list(&aws_smithy_schema::prelude::DOCUMENT, &mut |d| {
2280 items.push(d.read_string(&aws_smithy_schema::prelude::STRING)?);
2281 Ok(())
2282 })
2283 .unwrap();
2284 assert_eq!(items, vec!["1", "2"]);
2285 }
2286
2287 #[test]
2291 fn element_name_check_skips_map_children_not_named_entry() {
2292 static MAP_KEY: Schema<'static> =
2293 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
2294 static MAP_VALUE: Schema<'static> =
2295 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
2296 static MAP_SCHEMA: Schema<'static> =
2297 Schema::new_map(shape_id!("test", "M"), &MAP_KEY, &MAP_VALUE);
2298
2299 let xml = "<m><item><key>x</key><value>1</value></item>\
2300 <entry><key>a</key><value>2</value></entry></m>";
2301
2302 for (settings, expected) in [
2303 (element_name_settings(true), vec![("a", "2")]),
2304 (element_name_settings(false), vec![("a", "2"), ("x", "1")]),
2305 (
2306 Arc::new(XmlCodecSettings::default()),
2307 vec![("a", "2"), ("x", "1")],
2308 ),
2309 ] {
2310 let expected: Vec<(String, String)> = expected
2311 .into_iter()
2312 .map(|(k, v)| (k.to_owned(), v.to_owned()))
2313 .collect();
2314
2315 let mut out: Vec<_> = XmlDeserializer::new(xml.as_bytes(), settings.clone())
2316 .read_string_string_map(&MAP_SCHEMA)
2317 .unwrap()
2318 .into_iter()
2319 .collect();
2320 out.sort();
2321 assert_eq!(out, expected);
2322
2323 let mut entries = Vec::new();
2324 XmlDeserializer::new(xml.as_bytes(), settings)
2325 .read_map(&MAP_SCHEMA, &mut |k, d| {
2326 entries.push((k, d.read_string(&MAP_VALUE)?));
2327 Ok(())
2328 })
2329 .unwrap();
2330 entries.sort();
2331 assert_eq!(entries, expected);
2332 }
2333 }
2334
2335 #[test]
2338 fn element_name_check_applies_to_nested_collections() {
2339 static CELL: Schema<'static> = Schema::new_member(
2341 shape_id!("test", "Row$member"),
2342 ShapeType::String,
2343 "member",
2344 0,
2345 )
2346 .with_xml_name("Cell");
2347 static ROW: Schema<'static> = Schema::new_member(
2348 shape_id!("test", "Grid$member"),
2349 ShapeType::List,
2350 "member",
2351 0,
2352 )
2353 .with_list_member(&CELL);
2354 static GRID: Schema<'static> =
2355 Schema::new_member(shape_id!("test", "S$grid"), ShapeType::List, "grid", 0)
2356 .with_list_member(&ROW);
2357 static ATTR_KEY: Schema<'static> =
2359 Schema::new_member(shape_id!("test", "Attrs$key"), ShapeType::String, "key", 0);
2360 static ATTR_ITEM: Schema<'static> = Schema::new_member(
2361 shape_id!("test", "Values$member"),
2362 ShapeType::String,
2363 "member",
2364 0,
2365 );
2366 static ATTR_VALUE: Schema<'static> = Schema::new_member(
2367 shape_id!("test", "Attrs$value"),
2368 ShapeType::List,
2369 "value",
2370 1,
2371 )
2372 .with_list_member(&ATTR_ITEM);
2373 static ATTRS: Schema<'static> =
2374 Schema::new_member(shape_id!("test", "S$attrs"), ShapeType::Map, "attrs", 1)
2375 .with_map_members(&ATTR_KEY, &ATTR_VALUE);
2376
2377 fn grid(check_names: bool) -> Vec<Vec<String>> {
2378 let xml = b"<grid>\
2379 <member><Cell>1</Cell><member>x</member></member>\
2380 <row><Cell>9</Cell></row>\
2381 <member><Cell>2</Cell></member>\
2382 </grid>";
2383 let mut rows = Vec::new();
2384 XmlDeserializer::new(xml, element_name_settings(check_names))
2385 .read_list(&GRID, &mut |d| {
2386 let mut row = Vec::new();
2387 d.read_list(&ROW, &mut |d| {
2388 row.push(d.read_string(&CELL)?);
2389 Ok(())
2390 })?;
2391 rows.push(row);
2392 Ok(())
2393 })
2394 .unwrap();
2395 rows
2396 }
2397 assert_eq!(grid(true), vec![vec!["1"], vec!["2"]]);
2398 assert_eq!(grid(false), vec![vec!["1", "x"], vec!["9"], vec!["2"]]);
2399
2400 fn attrs(check_names: bool) -> Vec<(String, Vec<String>)> {
2401 let xml = b"<attrs>\
2402 <entry><key>k</key><value><member>a</member><item>b</item></value></entry>\
2403 <other><key>z</key><value><member>q</member></value></other>\
2404 </attrs>";
2405 let mut entries = Vec::new();
2406 XmlDeserializer::new(xml, element_name_settings(check_names))
2407 .read_map(&ATTRS, &mut |key, d| {
2408 entries.push((key, d.read_string_list(&ATTR_VALUE)?));
2409 Ok(())
2410 })
2411 .unwrap();
2412 entries.sort();
2413 entries
2414 }
2415 assert_eq!(attrs(true), vec![("k".to_owned(), vec!["a".to_owned()])]);
2416 assert_eq!(
2417 attrs(false),
2418 vec![
2419 ("k".to_owned(), vec!["a".to_owned(), "b".to_owned()]),
2420 ("z".to_owned(), vec!["q".to_owned()]),
2421 ]
2422 );
2423 }
2424
2425 #[test]
2429 fn element_name_check_applies_to_recursive_structures() {
2430 static NODE_NAME: Schema<'static> =
2431 Schema::new_member(shape_id!("test", "Node$name"), ShapeType::String, "name", 0);
2432 static NODE_LIST_MEMBER: Schema<'static> = Schema::new_member(
2433 shape_id!("test", "NodeList$member"),
2434 ShapeType::Structure,
2435 "member",
2436 0,
2437 );
2438 static NODE_CHILDREN: Schema<'static> = Schema::new_member(
2439 shape_id!("test", "Node$children"),
2440 ShapeType::List,
2441 "children",
2442 1,
2443 )
2444 .with_list_member(&NODE_LIST_MEMBER);
2445 static NODE: Schema<'static> = Schema::new_struct(
2446 shape_id!("test", "Node"),
2447 ShapeType::Structure,
2448 &[&NODE_NAME, &NODE_CHILDREN],
2449 );
2450
2451 #[derive(Debug, PartialEq)]
2452 struct Node(String, Vec<Node>);
2453
2454 fn read_node(d: &mut dyn ShapeDeserializer) -> Result<Node, SerdeError> {
2455 let mut node = Node(String::new(), Vec::new());
2456 d.read_struct(&NODE, &mut |member, d| {
2457 match member.member_name() {
2458 Some("name") => node.0 = d.read_string(member)?,
2459 Some("children") => d.read_list(member, &mut |d| {
2460 node.1.push(read_node(d)?);
2461 Ok(())
2462 })?,
2463 _ => {}
2464 }
2465 Ok(())
2466 })?;
2467 Ok(node)
2468 }
2469 fn leaf(name: &str) -> Node {
2470 Node(name.to_owned(), Vec::new())
2471 }
2472
2473 let xml = b"<Node><name>root</name><children>\
2474 <member><name>a</name><children>\
2475 <bogus><name>x</name></bogus>\
2476 <member><name>a1</name></member>\
2477 </children></member>\
2478 <item><name>skipped</name></item>\
2479 <member><name>b</name></member>\
2480 </children></Node>";
2481 let read = |check_names: bool| {
2482 read_node(&mut XmlDeserializer::new(
2483 xml,
2484 element_name_settings(check_names),
2485 ))
2486 .unwrap()
2487 };
2488 assert_eq!(
2489 read(true),
2490 Node(
2491 "root".to_owned(),
2492 vec![Node("a".to_owned(), vec![leaf("a1")]), leaf("b")]
2493 )
2494 );
2495 assert_eq!(
2496 read(false),
2497 Node(
2498 "root".to_owned(),
2499 vec![
2500 Node("a".to_owned(), vec![leaf("x"), leaf("a1")]),
2501 leaf("skipped"),
2502 leaf("b")
2503 ]
2504 )
2505 );
2506 }
2507
2508 #[test]
2509 fn read_blob_list_helper() {
2510 let xml = b"<blobs><member>aGVsbG8=</member><member>d29ybGQ=</member></blobs>";
2512 let settings = Arc::new(XmlCodecSettings::default());
2513 let mut deser = XmlDeserializer::new(xml, settings);
2514
2515 static LIST_MEMBER: Schema<'static> =
2516 Schema::new_member(shape_id!("test", "B$member"), ShapeType::Blob, "member", 0);
2517 static LIST_SCHEMA: Schema<'static> =
2518 Schema::new_list(shape_id!("test", "B"), &LIST_MEMBER);
2519
2520 let out = deser.read_blob_list(&LIST_SCHEMA).unwrap();
2521 assert_eq!(out.len(), 2);
2522 assert_eq!(out[0].as_ref(), b"hello");
2523 assert_eq!(out[1].as_ref(), b"world");
2524 }
2525
2526 #[test]
2527 fn read_blob_list_helper_rejects_invalid_base64() {
2528 let xml = b"<blobs><member>!!!not-base64!!!</member></blobs>";
2529 let settings = Arc::new(XmlCodecSettings::default());
2530 let mut deser = XmlDeserializer::new(xml, settings);
2531
2532 static LIST_MEMBER: Schema<'static> =
2533 Schema::new_member(shape_id!("test", "B$member"), ShapeType::Blob, "member", 0);
2534 static LIST_SCHEMA: Schema<'static> =
2535 Schema::new_list(shape_id!("test", "B"), &LIST_MEMBER);
2536
2537 let err = deser.read_blob_list(&LIST_SCHEMA).unwrap_err();
2538 assert!(format!("{err}").contains("base64"));
2539 }
2540
2541 #[test]
2542 fn read_integer_list_helper() {
2543 let xml = b"<nums><member>1</member><member>-42</member><member>0</member></nums>";
2544 let settings = Arc::new(XmlCodecSettings::default());
2545 let mut deser = XmlDeserializer::new(xml, settings);
2546
2547 static LIST_MEMBER: Schema<'static> = Schema::new_member(
2548 shape_id!("test", "I$member"),
2549 ShapeType::Integer,
2550 "member",
2551 0,
2552 );
2553 static LIST_SCHEMA: Schema<'static> =
2554 Schema::new_list(shape_id!("test", "I"), &LIST_MEMBER);
2555
2556 let out = deser.read_integer_list(&LIST_SCHEMA).unwrap();
2557 assert_eq!(out, vec![1i32, -42, 0]);
2558 }
2559
2560 #[test]
2561 fn read_long_list_helper() {
2562 let xml = b"<nums><member>9223372036854775807</member><member>-1</member></nums>";
2563 let settings = Arc::new(XmlCodecSettings::default());
2564 let mut deser = XmlDeserializer::new(xml, settings);
2565
2566 static LIST_MEMBER: Schema<'static> =
2567 Schema::new_member(shape_id!("test", "Lo$member"), ShapeType::Long, "member", 0);
2568 static LIST_SCHEMA: Schema<'static> =
2569 Schema::new_list(shape_id!("test", "Lo"), &LIST_MEMBER);
2570
2571 let out = deser.read_long_list(&LIST_SCHEMA).unwrap();
2572 assert_eq!(out, vec![i64::MAX, -1]);
2573 }
2574
2575 #[test]
2576 fn read_string_string_map_helper() {
2577 let xml = b"<m><entry><key>a</key><value>1</value></entry>\
2578 <entry><key>b</key><value>2</value></entry></m>";
2579 let settings = Arc::new(XmlCodecSettings::default());
2580 let mut deser = XmlDeserializer::new(xml, settings);
2581
2582 static MAP_KEY: Schema<'static> =
2583 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
2584 static MAP_VALUE: Schema<'static> =
2585 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 0);
2586 static MAP_SCHEMA: Schema<'static> =
2587 Schema::new_map(shape_id!("test", "M"), &MAP_KEY, &MAP_VALUE);
2588
2589 let out = deser.read_string_string_map(&MAP_SCHEMA).unwrap();
2590 assert_eq!(out.len(), 2);
2591 assert_eq!(out.get("a").map(String::as_str), Some("1"));
2592 assert_eq!(out.get("b").map(String::as_str), Some("2"));
2593 }
2594
2595 #[test]
2596 fn read_string_string_map_helper_with_renamed_key_value() {
2597 let xml = b"<m><entry><K>a</K><V>1</V></entry></m>";
2600 let settings = Arc::new(XmlCodecSettings::default());
2601 let mut deser = XmlDeserializer::new(xml, settings);
2602
2603 static MAP_KEY: Schema<'static> =
2604 Schema::new_member(shape_id!("test", "M2$key"), ShapeType::String, "key", 0)
2605 .with_xml_name("K");
2606 static MAP_VALUE: Schema<'static> =
2607 Schema::new_member(shape_id!("test", "M2$value"), ShapeType::String, "value", 0)
2608 .with_xml_name("V");
2609 static MAP_SCHEMA: Schema<'static> =
2610 Schema::new_map(shape_id!("test", "M2"), &MAP_KEY, &MAP_VALUE);
2611
2612 let out = deser.read_string_string_map(&MAP_SCHEMA).unwrap();
2613 assert_eq!(out.get("a").map(String::as_str), Some("1"));
2614 }
2615
2616 #[test]
2626 fn nested_struct_three_levels_deep() {
2627 static LEAF: Schema<'static> =
2628 Schema::new_member(shape_id!("t", "Inner"), ShapeType::String, "Leaf", 0);
2629 static INNER_SCHEMA: Schema<'static> =
2630 Schema::new_struct(shape_id!("t", "Inner"), ShapeType::Structure, &[&LEAF]);
2631 static INNER_MEMBER: Schema<'static> =
2632 Schema::new_member(shape_id!("t", "Middle"), ShapeType::Structure, "Inner", 0);
2633 static MIDDLE_SCHEMA: Schema<'static> = Schema::new_struct(
2634 shape_id!("t", "Middle"),
2635 ShapeType::Structure,
2636 &[&INNER_MEMBER],
2637 );
2638 static MIDDLE_MEMBER: Schema<'static> =
2639 Schema::new_member(shape_id!("t", "Outer"), ShapeType::Structure, "Middle", 0);
2640 static OUTER_SCHEMA: Schema<'static> = Schema::new_struct(
2641 shape_id!("t", "Outer"),
2642 ShapeType::Structure,
2643 &[&MIDDLE_MEMBER],
2644 );
2645 static OUTER_MEMBER: Schema<'static> =
2646 Schema::new_member(shape_id!("t", "Root"), ShapeType::Structure, "Outer", 0);
2647 static ROOT: Schema<'static> = Schema::new_struct(
2648 shape_id!("t", "Root"),
2649 ShapeType::Structure,
2650 &[&OUTER_MEMBER],
2651 );
2652
2653 let xml = b"<Root><Outer><Middle><Inner><Leaf>value</Leaf></Inner></Middle></Outer></Root>";
2654 let settings = Arc::new(XmlCodecSettings::default());
2655 let mut deser = XmlDeserializer::new(xml, settings);
2656 let mut leaf = String::new();
2657 deser
2658 .read_struct(&ROOT, &mut |outer_m, d_outer| {
2659 assert_eq!(outer_m.member_name(), Some("Outer"));
2660 d_outer.read_struct(&OUTER_SCHEMA, &mut |middle_m, d_middle| {
2661 assert_eq!(middle_m.member_name(), Some("Middle"));
2662 d_middle.read_struct(&MIDDLE_SCHEMA, &mut |inner_m, d_inner| {
2663 assert_eq!(inner_m.member_name(), Some("Inner"));
2664 d_inner.read_struct(&INNER_SCHEMA, &mut |leaf_m, d_leaf| {
2665 if leaf_m.member_name() == Some("Leaf") {
2666 leaf = d_leaf.read_string(leaf_m)?;
2667 }
2668 Ok(())
2669 })
2670 })
2671 })
2672 })
2673 .expect("3-level nested struct should round-trip");
2674 assert_eq!(leaf, "value");
2675 }
2676
2677 #[test]
2678 fn struct_member_with_escaped_text_round_trips() {
2679 static VALUE: Schema<'static> =
2680 Schema::new_member(shape_id!("t", "Body"), ShapeType::String, "value", 0);
2681 static BODY_SCHEMA: Schema<'static> =
2682 Schema::new_struct(shape_id!("t", "Body"), ShapeType::Structure, &[&VALUE]);
2683 static PAYLOAD_MEMBER: Schema<'static> = Schema::new_member(
2684 shape_id!("t", "Envelope"),
2685 ShapeType::Structure,
2686 "payload",
2687 0,
2688 );
2689 static ENVELOPE_SCHEMA: Schema<'static> = Schema::new_struct(
2690 shape_id!("t", "Envelope"),
2691 ShapeType::Structure,
2692 &[&PAYLOAD_MEMBER],
2693 );
2694
2695 let xml = b"<Envelope><payload><value>foo&bar</value></payload></Envelope>";
2700 let settings = Arc::new(XmlCodecSettings::default());
2701 let mut deser = XmlDeserializer::new(xml, settings);
2702 let mut value_str = String::new();
2703 deser
2704 .read_struct(&ENVELOPE_SCHEMA, &mut |payload_m, d_payload| {
2705 let _ = payload_m;
2706 d_payload.read_struct(&BODY_SCHEMA, &mut |inner_m, d_inner| {
2707 if inner_m.member_name() == Some("value") {
2708 value_str = d_inner.read_string(inner_m)?;
2709 }
2710 Ok(())
2711 })
2712 })
2713 .expect("escaped text inside a nested struct should round-trip");
2714 assert_eq!(value_str, "foo&bar");
2715 }
2716
2717 #[test]
2718 fn read_map_preserves_empty_string_key() {
2719 static KEY: Schema<'static> =
2722 Schema::new_member(shape_id!("t", "M$key"), ShapeType::String, "key", 0);
2723 static VALUE: Schema<'static> =
2724 Schema::new_member(shape_id!("t", "M$value"), ShapeType::String, "value", 1);
2725 static MAP: Schema<'static> = Schema::new_map(shape_id!("t", "M"), &KEY, &VALUE);
2726
2727 let xml = b"<Root><entry><key></key><value>v1</value></entry></Root>";
2728 let settings = Arc::new(XmlCodecSettings::default());
2729 let mut deser = XmlDeserializer::new(xml, settings);
2730
2731 let mut got: std::collections::HashMap<String, String> = Default::default();
2732 deser
2733 .read_map(&MAP, &mut |k, d| {
2734 let v = d.read_string(&VALUE)?;
2735 got.insert(k, v);
2736 Ok(())
2737 })
2738 .expect("empty-key entry should be preserved");
2739 assert_eq!(got.get("").map(String::as_str), Some("v1"));
2740 }
2741
2742 #[test]
2748 fn read_map_value_is_inner_map_with_renamed_inner_key_value() {
2749 let xml = b"<outerMap><entry><key>ok</key><value><entry><InnerKey>ik</InnerKey><InnerVal>iv</InnerVal></entry></value></entry></outerMap>";
2750 let settings = Arc::new(XmlCodecSettings::default());
2751 let mut deser = XmlDeserializer::new(xml, settings);
2752
2753 static INNER_KEY: Schema<'static> = Schema::new_member(
2754 shape_id!("test", "InnerMap$key"),
2755 ShapeType::String,
2756 "key",
2757 0,
2758 )
2759 .with_xml_name("InnerKey");
2760 static INNER_VAL: Schema<'static> = Schema::new_member(
2761 shape_id!("test", "InnerMap$value"),
2762 ShapeType::String,
2763 "value",
2764 1,
2765 )
2766 .with_xml_name("InnerVal");
2767
2768 static OUTER_VALUE: Schema<'static> = Schema::new_member(
2772 shape_id!("test", "OuterMap$value"),
2773 ShapeType::Map,
2774 "value",
2775 1,
2776 )
2777 .with_map_members(&INNER_KEY, &INNER_VAL);
2778
2779 static OUTER_KEY: Schema<'static> = Schema::new_member(
2780 shape_id!("test", "OuterMap$key"),
2781 ShapeType::String,
2782 "key",
2783 0,
2784 );
2785 static OUTER_MAP_SCHEMA: Schema<'static> =
2786 Schema::new_map(shape_id!("test", "OuterMap"), &OUTER_KEY, &OUTER_VALUE);
2787
2788 let mut got: Vec<(String, Vec<(String, String)>)> = Vec::new();
2789 deser
2790 .read_map(&OUTER_MAP_SCHEMA, &mut |outer_key, d| {
2791 let mut inner: Vec<(String, String)> = Vec::new();
2792 d.read_map(&OUTER_VALUE, &mut |inner_key, d2| {
2793 let inner_val = d2.read_string(&INNER_VAL)?;
2794 inner.push((inner_key, inner_val));
2795 Ok(())
2796 })?;
2797 got.push((outer_key, inner));
2798 Ok(())
2799 })
2800 .expect("nested map deserialization should succeed");
2801
2802 assert_eq!(
2803 got,
2804 vec![("ok".to_owned(), vec![("ik".to_owned(), "iv".to_owned())])]
2805 );
2806 }
2807
2808 #[test]
2813 fn read_list_member_is_inner_map_with_renamed_inner_key_value() {
2814 let xml = b"<items><member><entry><Attr>k1</Attr><Set>v1</Set></entry></member></items>";
2815 let settings = Arc::new(XmlCodecSettings::default());
2816 let mut deser = XmlDeserializer::new(xml, settings);
2817
2818 static INNER_KEY: Schema<'static> = Schema::new_member(
2819 shape_id!("test", "InnerMap$key"),
2820 ShapeType::String,
2821 "key",
2822 0,
2823 )
2824 .with_xml_name("Attr");
2825 static INNER_VAL: Schema<'static> = Schema::new_member(
2826 shape_id!("test", "InnerMap$value"),
2827 ShapeType::String,
2828 "value",
2829 1,
2830 )
2831 .with_xml_name("Set");
2832
2833 static LIST_ITEM: Schema<'static> = Schema::new_member(
2836 shape_id!("test", "OuterList$member"),
2837 ShapeType::Map,
2838 "member",
2839 0,
2840 )
2841 .with_map_members(&INNER_KEY, &INNER_VAL);
2842
2843 static OUTER_LIST_SCHEMA: Schema<'static> =
2844 Schema::new_list(shape_id!("test", "OuterList"), &LIST_ITEM);
2845
2846 let mut got: Vec<Vec<(String, String)>> = Vec::new();
2847 deser
2848 .read_list(&OUTER_LIST_SCHEMA, &mut |d| {
2849 let mut entries: Vec<(String, String)> = Vec::new();
2850 d.read_map(&LIST_ITEM, &mut |inner_key, d2| {
2851 let inner_val = d2.read_string(&INNER_VAL)?;
2852 entries.push((inner_key, inner_val));
2853 Ok(())
2854 })?;
2855 got.push(entries);
2856 Ok(())
2857 })
2858 .expect("list-of-map deserialization should succeed");
2859
2860 assert_eq!(got, vec![vec![("k1".to_owned(), "v1".to_owned())]]);
2861 }
2862}
2863
2864#[cfg(test)]
2871mod skip_value_contract {
2872 use super::*;
2873 use aws_smithy_schema::serde::ShapeDeserializer;
2874 use aws_smithy_schema::{shape_id, Schema, ShapeType};
2875
2876 static BOUND: Schema<'static> = Schema::new_member(
2877 shape_id!("test", "Output$bound"),
2878 ShapeType::String,
2879 "bound",
2880 0,
2881 );
2882 static BODY: Schema<'static> = Schema::new_member(
2883 shape_id!("test", "Output$body"),
2884 ShapeType::String,
2885 "body",
2886 1,
2887 );
2888 static TAIL: Schema<'static> = Schema::new_member(
2889 shape_id!("test", "Output$tail"),
2890 ShapeType::String,
2891 "tail",
2892 2,
2893 );
2894 static OUTPUT: Schema<'static> = Schema::new_struct(
2895 shape_id!("test", "Output"),
2896 ShapeType::Structure,
2897 &[&BOUND, &BODY, &TAIL],
2898 );
2899
2900 fn skip_bound(xml: &[u8]) -> Result<(Option<String>, Option<String>), SerdeError> {
2902 let mut deser = XmlDeserializer::new(xml, Arc::new(XmlCodecSettings::default()));
2903 let (mut body, mut tail) = (None, None);
2904 deser.read_struct(&OUTPUT, &mut |member, d| {
2905 match member.member_index() {
2906 Some(0) => d.skip_value()?,
2907 Some(1) => body = Some(d.read_string(member)?),
2908 Some(2) => tail = Some(d.read_string(member)?),
2909 _ => {}
2910 }
2911 Ok(())
2912 })?;
2913 Ok((body, tail))
2914 }
2915
2916 #[test]
2917 fn skipping_a_member_does_not_consume_its_siblings() {
2918 let xml = b"<Output><bound>skipped</bound><body>real</body><tail>end</tail></Output>";
2921 let (body, tail) = skip_bound(xml).unwrap();
2922 assert_eq!(body.as_deref(), Some("real"));
2923 assert_eq!(tail.as_deref(), Some("end"));
2924 }
2925
2926 #[test]
2927 fn skipping_works_regardless_of_element_order() {
2928 for xml in [
2929 &b"<Output><bound>s</bound><body>real</body><tail>end</tail></Output>"[..],
2930 &b"<Output><body>real</body><bound>s</bound><tail>end</tail></Output>"[..],
2931 &b"<Output><body>real</body><tail>end</tail><bound>s</bound></Output>"[..],
2932 ] {
2933 let (body, tail) = skip_bound(xml).unwrap();
2934 assert_eq!(
2935 (body.as_deref(), tail.as_deref()),
2936 (Some("real"), Some("end")),
2937 "failed for {}",
2938 String::from_utf8_lossy(xml)
2939 );
2940 }
2941 }
2942
2943 #[test]
2944 fn skipping_an_aggregate_member_with_nested_content_does_not_consume_siblings() {
2945 static AGG_BOUND: Schema<'static> = Schema::new_member(
2951 shape_id!("test", "Output$bound"),
2952 ShapeType::Structure,
2953 "bound",
2954 0,
2955 );
2956 static AGG_OUTPUT: Schema<'static> = Schema::new_struct(
2957 shape_id!("test", "Output"),
2958 ShapeType::Structure,
2959 &[&AGG_BOUND, &BODY, &TAIL],
2960 );
2961
2962 let xml = b"<Output><bound><inner>x</inner><body>decoy</body></bound>\
2966 <body>real</body><tail>end</tail></Output>";
2967 let mut deser = XmlDeserializer::new(xml, Arc::new(XmlCodecSettings::default()));
2968 let (mut body, mut tail) = (None, None);
2969 deser
2970 .read_struct(&AGG_OUTPUT, &mut |member, d| {
2971 match member.member_index() {
2972 Some(0) => d.skip_value()?,
2973 Some(1) => body = Some(d.read_string(member)?),
2974 Some(2) => tail = Some(d.read_string(member)?),
2975 _ => {}
2976 }
2977 Ok(())
2978 })
2979 .unwrap();
2980 assert_eq!(body.as_deref(), Some("real"));
2981 assert_eq!(tail.as_deref(), Some("end"));
2982 }
2983
2984 #[test]
2985 fn skipping_a_scalar_member_ignores_its_nested_content() {
2986 let xml = b"<Output><bound><body>decoy</body></bound>\
2987 <body>real</body><tail>end</tail></Output>";
2988 let (body, tail) = skip_bound(xml).unwrap();
2989 assert_eq!(body.as_deref(), Some("real"));
2990 assert_eq!(tail.as_deref(), Some("end"));
2991 }
2992
2993 #[test]
2994 fn reading_a_scalar_member_still_rejects_nested_content() {
2995 let xml = b"<Output><bound><body>decoy</body></bound>\
2996 <body>real</body><tail>end</tail></Output>";
2997 let mut deser = XmlDeserializer::new(xml, Arc::new(XmlCodecSettings::default()));
2998 let result = deser.read_struct(&OUTPUT, &mut |member, value| {
2999 value.read_string(member)?;
3000 Ok(())
3001 });
3002 assert!(result.is_err());
3003 }
3004
3005 #[test]
3006 fn skipping_a_self_closing_and_empty_element_is_fine() {
3007 for xml in [
3008 &b"<Output><bound/><body>real</body><tail>end</tail></Output>"[..],
3009 &b"<Output><bound></bound><body>real</body><tail>end</tail></Output>"[..],
3010 ] {
3011 let (body, tail) = skip_bound(xml).unwrap();
3012 assert_eq!(
3013 (body.as_deref(), tail.as_deref()),
3014 (Some("real"), Some("end")),
3015 "failed for {}",
3016 String::from_utf8_lossy(xml)
3017 );
3018 }
3019 }
3020
3021 #[test]
3022 fn skip_value_is_a_no_op_on_a_text_deserializer() {
3023 static V: Schema<'static> =
3027 Schema::new_member(shape_id!("test", "S$v"), ShapeType::String, "v", 0);
3028 let mut deser =
3029 XmlDeserializer::new(b"<v>hello</v>", Arc::new(XmlCodecSettings::default()));
3030 let dynamic: &mut dyn ShapeDeserializer = &mut deser;
3031 dynamic.skip_value().unwrap();
3032 assert_eq!(deser.read_string(&V).unwrap(), "hello");
3034 }
3035}