1use super::XmlCodecSettings;
16use aws_smithy_schema::codec::FinishSerializer;
17use aws_smithy_schema::serde::{SerdeError, SerializableStruct, ShapeSerializer};
18use aws_smithy_schema::Schema;
19use aws_smithy_types::date_time::Format as TimestampFormat;
20use aws_smithy_types::{BigDecimal, BigInteger, DateTime};
21
22use aws_smithy_schema::extension::SchemaExtensionKey;
23use aws_smithy_types::Document;
24use std::sync::Arc;
25
26type Namespace = (String, Option<String>);
28
29fn namespace_of(schema: Option<&Schema<'_>>) -> Option<Arc<Namespace>> {
30 schema
31 .and_then(|s| s.xml_namespace())
32 .map(|ns| Arc::new((ns.uri().to_owned(), ns.prefix().map(|p| p.to_owned()))))
33}
34
35fn member_element_name<'s>(member: Option<&'s Schema<'s>>, default: &'static str) -> &'s str {
37 member
38 .and_then(|m| m.xml_name().map(|n| n.value()).or(m.member_name()))
39 .unwrap_or(default)
40}
41
42#[derive(Debug)]
48struct XmlListNames {
49 item: Arc<str>,
53 item_namespace: Option<Arc<Namespace>>,
55}
56
57static XML_LIST_NAMES: SchemaExtensionKey<XmlListNames> =
58 SchemaExtensionKey::new(|list| XmlListNames {
59 item: Arc::from(if list.xml_flattened() {
60 XmlSerializer::element_name(list)
61 } else {
62 member_element_name(list.member(), "member")
63 }),
64 item_namespace: namespace_of(list.member()),
65 });
66
67#[derive(Debug)]
70struct XmlMapNames {
71 entry: Arc<str>,
72 key: Arc<str>,
73 value: Arc<str>,
74 key_namespace: Option<Arc<Namespace>>,
75 value_namespace: Option<Arc<Namespace>>,
76}
77
78static XML_MAP_NAMES: SchemaExtensionKey<XmlMapNames> =
79 SchemaExtensionKey::new(|map| XmlMapNames {
80 entry: Arc::from(if map.xml_flattened() {
81 XmlSerializer::element_name(map)
82 } else {
83 "entry"
84 }),
85 key: Arc::from(member_element_name(map.key(), "key")),
86 value: Arc::from(member_element_name(map.member(), "value")),
87 key_namespace: namespace_of(map.key()),
88 value_namespace: namespace_of(map.member()),
89 });
90
91pub struct XmlSerializer {
93 output: String,
94 settings: Arc<XmlCodecSettings>,
95 frames: Vec<Frame>,
99 map_state: Option<MapState>,
101 list_item_name: Option<Arc<str>>,
103 list_item_namespace: Option<Arc<Namespace>>,
107 member_filter: MemberFilter,
138 next_root_xml_name: Option<String>,
147 next_root_xml_namespace: Option<(String, Option<String>)>,
157}
158
159#[derive(Debug, Copy, Clone, PartialEq, Eq)]
160enum MemberFilter {
161 None,
163 AttributesOnly,
165 NonAttributesOnly,
167}
168
169#[derive(Debug)]
171struct MapState {
172 entry_name: Arc<str>,
174 key_name: Arc<str>,
176 value_name: Arc<str>,
178 key_namespace: Option<Arc<Namespace>>,
180 value_namespace: Option<Arc<Namespace>>,
182 expecting_key: bool,
184}
185
186#[derive(Debug)]
191enum Frame {
192 StartTagPending { attrs: String },
197 Open,
199}
200
201fn write_xmlns_attr(out: &mut String, ns: Option<&Namespace>) {
214 use std::fmt::Write;
215 match ns {
216 Some((uri, Some(prefix))) => {
217 write!(out, " xmlns:{prefix}=\"{uri}\"").unwrap();
218 }
219 Some((uri, None)) => {
220 write!(out, " xmlns=\"{uri}\"").unwrap();
221 }
222 None => {}
223 }
224}
225
226impl XmlSerializer {
227 pub(crate) fn new(settings: Arc<XmlCodecSettings>) -> Self {
229 Self {
230 output: String::new(),
231 settings,
232 frames: Vec::new(),
233 map_state: None,
234 list_item_name: None,
235 list_item_namespace: None,
236 member_filter: MemberFilter::None,
237 next_root_xml_name: None,
238 next_root_xml_namespace: None,
239 }
240 }
241
242 pub fn set_next_root_xml_name(&mut self, name: String) {
249 self.next_root_xml_name = Some(name);
250 }
251
252 pub fn set_next_root_xml_namespace(&mut self, uri: String, prefix: Option<String>) {
259 self.next_root_xml_namespace = Some((uri, prefix));
260 }
261
262 fn filter_allows(&self, schema: &Schema<'_>) -> bool {
265 match self.member_filter {
266 MemberFilter::None => true,
267 MemberFilter::AttributesOnly => schema.xml_attribute(),
268 MemberFilter::NonAttributesOnly => !schema.xml_attribute(),
269 }
270 }
271
272 fn element_name<'a>(schema: &'a Schema<'a>) -> &'a str {
282 schema
283 .xml_name()
284 .map(|t| t.value())
285 .or_else(|| schema.original_name())
286 .or_else(|| schema.member_name())
287 .unwrap_or_else(|| schema.shape_id().shape_name())
288 }
289
290 fn flush_start_tag(&mut self) {
295 if let Some(frame) = self.frames.last_mut() {
296 if let Frame::StartTagPending { attrs } = frame {
297 self.output.push_str(attrs);
298 self.output.push('>');
299 *frame = Frame::Open;
300 }
301 }
302 }
303
304 fn open_element(&mut self, name: &str) {
309 self.output.push('<');
310 self.output.push_str(name);
311 self.frames.push(Frame::StartTagPending {
312 attrs: String::new(),
313 });
314 }
315
316 fn write_xmlns(&mut self, schema: &Schema<'_>, inherited: Option<&Namespace>) {
330 use std::fmt::Write;
331 let is_document_root = self.frames.len() == 1;
332 let root_override =
337 if is_document_root && schema.xml_namespace().is_none() && inherited.is_none() {
338 self.next_root_xml_namespace.take()
339 } else {
340 None
341 };
342 let Some(Frame::StartTagPending { attrs, .. }) = self.frames.last_mut() else {
343 return;
344 };
345 if let Some(ns) = schema.xml_namespace() {
346 match ns.prefix() {
347 Some(prefix) => write!(attrs, " xmlns:{prefix}=\"{}\"", ns.uri()).unwrap(),
348 None => write!(attrs, " xmlns=\"{}\"", ns.uri()).unwrap(),
349 }
350 } else if let Some((uri, prefix)) = inherited {
351 match prefix.as_deref() {
352 Some(p) => write!(attrs, " xmlns:{p}=\"{uri}\"").unwrap(),
353 None => write!(attrs, " xmlns=\"{uri}\"").unwrap(),
354 }
355 } else if let Some((uri, prefix)) = root_override {
356 match prefix {
357 Some(p) => write!(attrs, " xmlns:{p}=\"{uri}\"").unwrap(),
358 None => write!(attrs, " xmlns=\"{uri}\"").unwrap(),
359 }
360 }
361 }
362
363 fn close_element(&mut self, name: &str) {
373 let frame = self
374 .frames
375 .pop()
376 .expect("close_element called with empty frame stack");
377 if let Frame::StartTagPending { attrs } = frame {
378 self.output.push_str(&attrs);
379 self.output.push('>');
380 }
381 self.output.push_str("</");
382 self.output.push_str(name);
383 self.output.push('>');
384 }
385
386 fn resolve_name<'s>(
392 &self,
393 schema: &'s Schema<'s>,
394 inherited: &'s mut Option<Arc<str>>,
395 ) -> &'s str {
396 if schema.xml_name().is_none() {
397 inherited.clone_from(&self.list_item_name);
398 }
399 match inherited {
400 Some(name) => name,
401 None => Self::element_name(schema),
402 }
403 }
404
405 fn write_safe_element(&mut self, schema: &Schema<'_>, content: &str) {
410 if !self.filter_allows(schema) {
411 return;
412 }
413 if self.try_write_attribute(schema, content) {
414 return;
415 }
416 use std::fmt::Write;
417 self.flush_start_tag();
418 if let Some(map_state) = &mut self.map_state {
419 if map_state.expecting_key {
420 let (entry, key) = (&map_state.entry_name, &map_state.key_name);
422 write!(self.output, "<{entry}><{key}").unwrap();
423 write_xmlns_attr(&mut self.output, map_state.key_namespace.as_deref());
424 write!(self.output, ">{content}</{key}>").unwrap();
425 map_state.expecting_key = false;
426 } else {
427 let (entry, value) = (&map_state.entry_name, &map_state.value_name);
429 write!(self.output, "<{value}").unwrap();
430 write_xmlns_attr(&mut self.output, map_state.value_namespace.as_deref());
431 write!(self.output, ">{content}</{value}></{entry}>").unwrap();
432 map_state.expecting_key = true;
433 }
434 } else {
435 let mut inherited_name = None;
436 let name = self.resolve_name(schema, &mut inherited_name);
437 self.open_element(name);
440 let inherited = self.list_item_namespace.clone();
441 self.write_xmlns(schema, inherited.as_deref());
442 self.flush_start_tag();
443 self.output.push_str(content);
444 self.close_element(name);
445 }
446 }
447
448 fn try_write_attribute(&mut self, schema: &Schema<'_>, value: &str) -> bool {
453 use std::fmt::Write;
454 if !schema.xml_attribute() {
455 return false;
456 }
457 if let Some(Frame::StartTagPending { attrs, .. }) = self.frames.last_mut() {
463 let name = Self::element_name(schema);
464 let escaped = crate::escape::escape(value);
465 write!(attrs, " {name}=\"{escaped}\"").unwrap();
466 return true;
467 }
468 false
469 }
470
471 fn resolve_timestamp_format(&self, schema: &Schema<'_>) -> Result<TimestampFormat, SerdeError> {
475 let Some(t) = schema.timestamp_format() else {
476 return Ok(self.settings.default_timestamp_format());
477 };
478 Ok(match t.format() {
479 aws_smithy_schema::traits::TimestampFormat::EpochSeconds => {
480 TimestampFormat::EpochSeconds
481 }
482 aws_smithy_schema::traits::TimestampFormat::DateTime => TimestampFormat::DateTime,
483 aws_smithy_schema::traits::TimestampFormat::HttpDate => TimestampFormat::HttpDate,
484 other => {
485 return Err(SerdeError::unsupported(format!(
486 "unsupported timestamp format {other:?}"
487 )))
488 }
489 })
490 }
491}
492
493impl FinishSerializer for XmlSerializer {
494 fn finish(self) -> Vec<u8> {
495 debug_assert!(
496 self.frames.is_empty(),
497 "XmlSerializer::finish called with {} unclosed frame(s)",
498 self.frames.len()
499 );
500 self.output.into_bytes()
501 }
502}
503
504impl ShapeSerializer for XmlSerializer {
505 fn write_struct(
506 &mut self,
507 schema: &Schema<'_>,
508 value: &dyn SerializableStruct,
509 ) -> Result<(), SerdeError> {
510 if schema.xml_attribute() {
511 return Err(SerdeError::custom(
512 "@xmlAttribute is not supported on aggregate types",
513 ));
514 }
515 if !self.filter_allows(schema) {
516 return Ok(());
517 }
518 self.flush_start_tag();
519
520 let in_map_value = if let Some(map_state) = &mut self.map_state {
522 if map_state.expecting_key {
523 false
524 } else {
525 use std::fmt::Write;
530 write!(self.output, "<{}>", map_state.value_name).unwrap();
531 map_state.expecting_key = true;
532 true
533 }
534 } else {
535 false
536 };
537
538 let saved_map_state = if in_map_value {
540 self.map_state.take()
541 } else {
542 None
543 };
544
545 if in_map_value {
546 let saved_filter = self.member_filter;
557 let has_attrs = schema.member_name().is_some()
563 || schema.members().iter().any(|m| m.xml_attribute());
564 if has_attrs {
565 self.member_filter = MemberFilter::AttributesOnly;
566 value.serialize_members(self)?;
567 }
568 self.member_filter = MemberFilter::NonAttributesOnly;
569 value.serialize_members(self)?;
570 self.member_filter = saved_filter;
571 use std::fmt::Write;
573 let saved = saved_map_state.as_ref().unwrap();
574 let val_name = &saved.value_name;
575 let entry = &saved.entry_name;
576 write!(self.output, "</{val_name}></{entry}>").unwrap();
577 self.map_state = saved_map_state;
578 } else {
579 let root_override = if self.frames.is_empty() {
585 self.next_root_xml_name.take().or_else(|| {
586 schema
587 .traits()
588 .and_then(|traits| traits.get_fqn("smithy.api#error"))
589 .and(self.settings.error_root_name)
590 .map(str::to_owned)
591 })
592 } else {
593 None
594 };
595 let saved_list_item = self.list_item_name.take();
596 let name = root_override
597 .as_deref()
598 .or(saved_list_item.as_deref())
599 .unwrap_or_else(|| Self::element_name(schema));
600 self.open_element(name);
601 self.write_xmlns(schema, None);
602 let saved_filter = self.member_filter;
620 let has_attrs = schema.member_name().is_some()
621 || schema.members().iter().any(|m| m.xml_attribute());
622 if has_attrs {
623 self.member_filter = MemberFilter::AttributesOnly;
624 value.serialize_members(self)?;
625 }
626 self.member_filter = MemberFilter::NonAttributesOnly;
627 value.serialize_members(self)?;
628 self.member_filter = saved_filter;
629 self.close_element(name);
630 self.list_item_name = saved_list_item;
631 }
632 Ok(())
633 }
634
635 fn write_list(
636 &mut self,
637 schema: &Schema<'_>,
638 write_elements: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
639 ) -> Result<(), SerdeError> {
640 if schema.xml_attribute() {
641 return Err(SerdeError::custom(
642 "@xmlAttribute is not supported on aggregate types",
643 ));
644 }
645 if !self.filter_allows(schema) {
646 return Ok(());
647 }
648
649 self.flush_start_tag();
650
651 let in_map_value = if let Some(map_state) = &mut self.map_state {
653 if !map_state.expecting_key {
654 use std::fmt::Write;
655 write!(self.output, "<{}>", map_state.value_name).unwrap();
656 map_state.expecting_key = true;
657 true
658 } else {
659 false
660 }
661 } else {
662 false
663 };
664 let saved_map_state = if in_map_value {
665 self.map_state.take()
666 } else {
667 None
668 };
669
670 let names = schema.extension(&XML_LIST_NAMES);
680 let item_name = if schema.xml_flattened() && schema.xml_name().is_none() {
681 self.list_item_name
683 .clone()
684 .unwrap_or_else(|| names.item.clone())
685 } else {
686 names.item.clone()
687 };
688 let mut inherited_name = None;
696 let wrapper_name = self.resolve_name(schema, &mut inherited_name);
697
698 let saved_list_item = self.list_item_name.take();
699 self.list_item_name = Some(item_name);
700
701 let saved_list_item_ns =
707 std::mem::replace(&mut self.list_item_namespace, names.item_namespace.clone());
708
709 if schema.xml_flattened() || in_map_value {
710 write_elements(self)?;
711 } else {
712 self.open_element(wrapper_name);
713 self.write_xmlns(schema, None);
716 write_elements(self)?;
717 self.close_element(wrapper_name);
718 }
719
720 self.list_item_name = saved_list_item;
721 self.list_item_namespace = saved_list_item_ns;
722
723 if in_map_value {
724 use std::fmt::Write;
725 let saved = saved_map_state.as_ref().unwrap();
726 let val_name = &saved.value_name;
727 let entry = &saved.entry_name;
728 write!(self.output, "</{val_name}></{entry}>").unwrap();
729 self.map_state = saved_map_state;
730 }
731 Ok(())
732 }
733
734 fn write_map(
735 &mut self,
736 schema: &Schema<'_>,
737 write_entries: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
738 ) -> Result<(), SerdeError> {
739 if schema.xml_attribute() {
740 return Err(SerdeError::custom(
741 "@xmlAttribute is not supported on aggregate types",
742 ));
743 }
744 if !self.filter_allows(schema) {
745 return Ok(());
746 }
747
748 self.flush_start_tag();
749
750 let in_map_value = if let Some(map_state) = &mut self.map_state {
752 if !map_state.expecting_key {
753 use std::fmt::Write;
754 write!(self.output, "<{}>", map_state.value_name).unwrap();
755 map_state.expecting_key = true;
756 true
757 } else {
758 false
759 }
760 } else {
761 false
762 };
763
764 let outer_map_state = self.map_state.take();
765
766 let names = schema.extension(&XML_MAP_NAMES);
768 self.map_state = Some(MapState {
769 entry_name: names.entry.clone(),
770 key_name: names.key.clone(),
771 value_name: names.value.clone(),
772 key_namespace: names.key_namespace.clone(),
773 value_namespace: names.value_namespace.clone(),
774 expecting_key: true,
775 });
776
777 let mut inherited_name = None;
784 let wrapper_name = self.resolve_name(schema, &mut inherited_name);
785
786 let saved_list_item = self.list_item_name.take();
789
790 if schema.xml_flattened() || in_map_value {
791 write_entries(self)?;
792 } else {
793 self.open_element(wrapper_name);
794 self.write_xmlns(schema, None);
795 write_entries(self)?;
796 self.close_element(wrapper_name);
797 }
798
799 self.list_item_name = saved_list_item;
800
801 self.map_state = outer_map_state;
802
803 if in_map_value {
804 use std::fmt::Write;
805 let saved = self.map_state.as_ref().unwrap();
806 let val_name = &saved.value_name;
807 let entry = &saved.entry_name;
808 write!(self.output, "</{val_name}></{entry}>").unwrap();
809 }
810 Ok(())
811 }
812
813 fn write_boolean(&mut self, schema: &Schema<'_>, value: bool) -> Result<(), SerdeError> {
814 self.write_safe_element(schema, if value { "true" } else { "false" });
815 Ok(())
816 }
817
818 fn write_byte(&mut self, schema: &Schema<'_>, value: i8) -> Result<(), SerdeError> {
819 self.write_safe_element(schema, &value.to_string());
820 Ok(())
821 }
822
823 fn write_short(&mut self, schema: &Schema<'_>, value: i16) -> Result<(), SerdeError> {
824 self.write_safe_element(schema, &value.to_string());
825 Ok(())
826 }
827
828 fn write_integer(&mut self, schema: &Schema<'_>, value: i32) -> Result<(), SerdeError> {
829 self.write_safe_element(schema, &value.to_string());
830 Ok(())
831 }
832
833 fn write_long(&mut self, schema: &Schema<'_>, value: i64) -> Result<(), SerdeError> {
834 self.write_safe_element(schema, &value.to_string());
835 Ok(())
836 }
837
838 fn write_float(&mut self, schema: &Schema<'_>, value: f32) -> Result<(), SerdeError> {
839 let text = if value.is_nan() {
840 "NaN".to_owned()
841 } else if value.is_infinite() {
842 if value.is_sign_positive() {
843 "Infinity".to_owned()
844 } else {
845 "-Infinity".to_owned()
846 }
847 } else {
848 value.to_string()
849 };
850 self.write_safe_element(schema, &text);
851 Ok(())
852 }
853
854 fn write_double(&mut self, schema: &Schema<'_>, value: f64) -> Result<(), SerdeError> {
855 let text = if value.is_nan() {
856 "NaN".to_owned()
857 } else if value.is_infinite() {
858 if value.is_sign_positive() {
859 "Infinity".to_owned()
860 } else {
861 "-Infinity".to_owned()
862 }
863 } else {
864 value.to_string()
865 };
866 self.write_safe_element(schema, &text);
867 Ok(())
868 }
869
870 fn write_big_integer(
871 &mut self,
872 schema: &Schema<'_>,
873 value: &BigInteger,
874 ) -> Result<(), SerdeError> {
875 self.write_safe_element(schema, value.as_ref());
876 Ok(())
877 }
878
879 fn write_big_decimal(
880 &mut self,
881 schema: &Schema<'_>,
882 value: &BigDecimal,
883 ) -> Result<(), SerdeError> {
884 self.write_safe_element(schema, value.as_ref());
885 Ok(())
886 }
887
888 fn write_string(&mut self, schema: &Schema<'_>, value: &str) -> Result<(), SerdeError> {
889 if !self.filter_allows(schema) {
890 return Ok(());
891 }
892 if self.try_write_attribute(schema, value) {
893 return Ok(());
894 }
895 use std::fmt::Write;
896 self.flush_start_tag();
897 let escaped = crate::escape::escape(value);
898 if let Some(map_state) = &mut self.map_state {
899 if map_state.expecting_key {
900 let (entry, key) = (&map_state.entry_name, &map_state.key_name);
901 write!(self.output, "<{entry}><{key}").unwrap();
902 write_xmlns_attr(&mut self.output, map_state.key_namespace.as_deref());
903 write!(self.output, ">{escaped}</{key}>").unwrap();
904 map_state.expecting_key = false;
905 } else {
906 let (entry, val_name) = (&map_state.entry_name, &map_state.value_name);
907 write!(self.output, "<{val_name}").unwrap();
908 write_xmlns_attr(&mut self.output, map_state.value_namespace.as_deref());
909 write!(self.output, ">{escaped}</{val_name}></{entry}>").unwrap();
910 map_state.expecting_key = true;
911 }
912 } else {
913 let mut inherited_name = None;
914 let name = self.resolve_name(schema, &mut inherited_name);
915 self.open_element(name);
918 let inherited = self.list_item_namespace.clone();
919 self.write_xmlns(schema, inherited.as_deref());
920 self.flush_start_tag();
921 self.output.push_str(&escaped);
922 self.close_element(name);
923 }
924 Ok(())
925 }
926
927 fn write_blob(
928 &mut self,
929 schema: &Schema<'_>,
930 value: aws_smithy_types::Blob,
931 ) -> Result<(), SerdeError> {
932 let encoded = aws_smithy_types::base64::encode(value.as_ref());
933 self.write_safe_element(schema, &encoded);
934 Ok(())
935 }
936
937 fn write_timestamp(&mut self, schema: &Schema<'_>, value: &DateTime) -> Result<(), SerdeError> {
938 let format = self.resolve_timestamp_format(schema)?;
939 let formatted = value
940 .fmt(format)
941 .map_err(|e| SerdeError::custom(e.to_string()))?;
942 self.write_safe_element(schema, &formatted);
944 Ok(())
945 }
946
947 fn write_document(
948 &mut self,
949 _schema: &Schema<'_>,
950 _value: &Document,
951 ) -> Result<(), SerdeError> {
952 Err(SerdeError::custom(
953 "document types are not supported by REST XML",
954 ))
955 }
956
957 fn write_null(&mut self, _schema: &Schema<'_>) -> Result<(), SerdeError> {
958 Ok(())
962 }
963}
964
965#[cfg(test)]
966mod tests {
967 use super::*;
968 use aws_smithy_schema::{prelude, shape_id, Schema, ShapeType};
969 use aws_smithy_types::Blob;
970
971 static NAME_MEMBER: Schema<'static> = Schema::new_member(
973 shape_id!("test", "Person$name"),
974 ShapeType::String,
975 "name",
976 0,
977 );
978 static PERSON_SCHEMA: Schema<'static> = Schema::new_struct(
979 shape_id!("test", "Person"),
980 ShapeType::Structure,
981 &[&NAME_MEMBER],
982 );
983
984 struct Person<'a> {
985 name: &'a str,
986 }
987
988 impl SerializableStruct for Person<'_> {
989 fn schema(&self) -> &Schema<'_> {
990 &PERSON_SCHEMA
991 }
992
993 fn serialize_members(
994 &self,
995 serializer: &mut dyn ShapeSerializer,
996 ) -> Result<(), SerdeError> {
997 serializer.write_string(&NAME_MEMBER, self.name)
998 }
999 }
1000
1001 fn serialize<F>(write: F) -> String
1002 where
1003 F: FnOnce(&mut XmlSerializer) -> Result<(), SerdeError>,
1004 {
1005 let mut ser = XmlSerializer::new(Arc::new(XmlCodecSettings::default()));
1006 write(&mut ser).expect("serialization failed");
1007 String::from_utf8(<XmlSerializer as FinishSerializer>::finish(ser)).unwrap()
1008 }
1009
1010 #[test]
1011 fn nested_collections_use_member_and_map_value_schemas() {
1012 static CELL: Schema<'static> = Schema::new_member(
1013 shape_id!("test", "NestedCollectionsMatrixListMemberList", "member"),
1014 ShapeType::Short,
1015 "member",
1016 0,
1017 );
1018 static ROW: Schema<'static> = Schema::new_member(
1019 shape_id!("test", "NestedCollectionsMatrixList", "member"),
1020 ShapeType::List,
1021 "member",
1022 0,
1023 )
1024 .with_list_member(&CELL);
1025 static MATRIX: Schema<'static> = Schema::new_member(
1026 shape_id!("test", "NestedCollections", "matrix"),
1027 ShapeType::List,
1028 "matrix",
1029 0,
1030 )
1031 .with_list_member(&ROW);
1032 static KEY: Schema<'static> = Schema::new_member(
1033 shape_id!("test", "NestedCollectionsValuesMap", "key"),
1034 ShapeType::String,
1035 "key",
1036 0,
1037 );
1038 static FLAG: Schema<'static> = Schema::new_member(
1039 shape_id!("test", "NestedCollectionsValuesMapValueList", "member"),
1040 ShapeType::Boolean,
1041 "member",
1042 0,
1043 );
1044 static VALUE: Schema<'static> = Schema::new_member(
1045 shape_id!("test", "NestedCollectionsValuesMap", "value"),
1046 ShapeType::List,
1047 "value",
1048 1,
1049 )
1050 .with_list_member(&FLAG);
1051 static VALUES: Schema<'static> = Schema::new_member(
1052 shape_id!("test", "NestedCollections", "values"),
1053 ShapeType::Map,
1054 "values",
1055 1,
1056 )
1057 .with_map_members(&KEY, &VALUE);
1058 static COLLECTIONS: Schema<'static> = Schema::new_struct(
1059 shape_id!("test", "NestedCollections"),
1060 ShapeType::Structure,
1061 &[&MATRIX, &VALUES],
1062 );
1063 struct NestedCollections {
1064 matrix: Vec<Vec<i16>>,
1065 values: std::collections::HashMap<String, Vec<bool>>,
1066 }
1067 impl SerializableStruct for NestedCollections {
1068 fn schema(&self) -> &Schema<'_> {
1069 &COLLECTIONS
1070 }
1071
1072 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1073 ser.write_list(&MATRIX, &|ser| {
1074 for row in &self.matrix {
1075 ser.write_list(&ROW, &|ser| {
1076 for cell in row {
1077 ser.write_short(&CELL, *cell)?;
1078 }
1079 Ok(())
1080 })?;
1081 }
1082 Ok(())
1083 })?;
1084 ser.write_map(&VALUES, &|ser| {
1085 for (key, flags) in &self.values {
1086 ser.write_string(&KEY, key)?;
1087 ser.write_list(&VALUE, &|ser| {
1088 for flag in flags {
1089 ser.write_boolean(&FLAG, *flag)?;
1090 }
1091 Ok(())
1092 })?;
1093 }
1094 Ok(())
1095 })
1096 }
1097 }
1098 let value = NestedCollections {
1099 matrix: vec![vec![1, 2]],
1100 values: std::collections::HashMap::from([("flags".into(), vec![false, true])]),
1101 };
1102 let output = serialize(|ser| ser.write_struct(&COLLECTIONS, &value));
1103 assert_eq!(output, "<NestedCollections><matrix><member><member>1</member><member>2</member></member></matrix><values><entry><key>flags</key><value><member>false</member><member>true</member></value></entry></values></NestedCollections>");
1104 }
1105
1106 #[test]
1107 fn struct_with_string_member() {
1108 let p = Person { name: "Iago" };
1109 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &p));
1110 assert_eq!(out, "<Person><name>Iago</name></Person>");
1111 }
1112
1113 #[test]
1114 fn list_item_names_override_union_target_xml_name() {
1115 static TEXT: Schema<'static> = Schema::new_member(
1116 shape_id!("test", "Choice", "text"),
1117 ShapeType::String,
1118 "text",
1119 0,
1120 );
1121 static CHOICE: Schema<'static> =
1122 Schema::new_struct(shape_id!("test", "Choice"), ShapeType::Union, &[&TEXT])
1123 .with_xml_name("ChoiceTargetRoot");
1124 struct Choice;
1125 impl SerializableStruct for Choice {
1126 fn schema(&self) -> &Schema<'_> {
1127 &CHOICE
1128 }
1129
1130 fn serialize_members(
1131 &self,
1132 serializer: &mut dyn ShapeSerializer,
1133 ) -> Result<(), SerdeError> {
1134 serializer.write_string(&TEXT, "hello")
1135 }
1136 }
1137 let member = Schema::new_member(
1138 shape_id!("test", "Choices", "member"),
1139 ShapeType::Union,
1140 "member",
1141 0,
1142 );
1143 let renamed = Schema::new_member(
1144 shape_id!("test", "Choices", "member"),
1145 ShapeType::Union,
1146 "member",
1147 0,
1148 )
1149 .with_xml_name("item");
1150 for (item_schema, flattened, expected) in [
1151 (
1152 &member,
1153 false,
1154 "<choices><member><text>hello</text></member></choices>",
1155 ),
1156 (
1157 &renamed,
1158 false,
1159 "<choices><item><text>hello</text></item></choices>",
1160 ),
1161 (&member, true, "<choices><text>hello</text></choices>"),
1162 ] {
1163 let mut list = Schema::new_member(
1164 shape_id!("test", "Output", "choices"),
1165 ShapeType::List,
1166 "choices",
1167 0,
1168 )
1169 .with_list_member(item_schema);
1170 if flattened {
1171 list = list.with_xml_flattened();
1172 }
1173 let output = serialize(|serializer| {
1174 serializer.write_list(&list, &|serializer| {
1175 serializer.write_struct(&CHOICE, &Choice)
1176 })
1177 });
1178 assert_eq!(output, expected);
1179 }
1180 assert_eq!(
1181 serialize(|serializer| serializer.write_struct(&CHOICE, &Choice)),
1182 "<ChoiceTargetRoot><text>hello</text></ChoiceTargetRoot>",
1183 );
1184 }
1185
1186 #[test]
1187 fn struct_with_no_members_self_closes() {
1188 struct Empty;
1189 impl SerializableStruct for Empty {
1190 fn schema(&self) -> &Schema<'_> {
1191 &EMPTY_SCHEMA
1192 }
1193
1194 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1195 Ok(())
1196 }
1197 }
1198 static EMPTY_SCHEMA: Schema<'static> =
1199 Schema::new_struct(shape_id!("test", "Empty"), ShapeType::Structure, &[]);
1200
1201 let out = serialize(|ser| ser.write_struct(&EMPTY_SCHEMA, &Empty));
1202 assert_eq!(out, "<Empty></Empty>");
1203 }
1204
1205 #[test]
1206 fn struct_string_value_is_escaped() {
1207 let p = Person { name: "<a&b>" };
1208 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &p));
1209 assert_eq!(out, "<Person><name><a&b></name></Person>");
1210 }
1211
1212 #[test]
1213 fn struct_string_value_eol_is_encoded() {
1214 let p = Person { name: "a\r\nb" };
1217 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &p));
1218 assert_eq!(out, "<Person><name>a
b</name></Person>");
1219 }
1220
1221 #[test]
1222 fn nested_structs_close_correctly() {
1223 static INNER_NAME: Schema<'static> = Schema::new_member(
1229 shape_id!("test", "Inner$name"),
1230 ShapeType::String,
1231 "name",
1232 0,
1233 );
1234 static OUTER_INNER: Schema<'static> = Schema::new_member(
1235 shape_id!("test", "Outer$inner"),
1236 ShapeType::Structure,
1237 "inner",
1238 0,
1239 );
1240 static OUTER_SCHEMA: Schema<'static> = Schema::new_struct(
1241 shape_id!("test", "Outer"),
1242 ShapeType::Structure,
1243 &[&OUTER_INNER],
1244 );
1245
1246 struct Inner<'a> {
1247 name: &'a str,
1248 }
1249 impl SerializableStruct for Inner<'_> {
1250 fn schema(&self) -> &Schema<'_> {
1251 static SCHEMA: Schema<'static> = Schema::new_struct(
1252 aws_smithy_schema::shape_id!("test", "Inner"),
1253 aws_smithy_schema::ShapeType::Structure,
1254 &[&INNER_NAME],
1255 );
1256 &SCHEMA
1257 }
1258
1259 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1260 ser.write_string(&INNER_NAME, self.name)
1261 }
1262 }
1263 struct Outer<'a> {
1264 inner: Inner<'a>,
1265 }
1266 impl SerializableStruct for Outer<'_> {
1267 fn schema(&self) -> &Schema<'_> {
1268 &OUTER_SCHEMA
1269 }
1270
1271 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1272 ser.write_struct(&OUTER_INNER, &self.inner)
1276 }
1277 }
1278
1279 let o = Outer {
1280 inner: Inner { name: "v" },
1281 };
1282 let out = serialize(|ser| ser.write_struct(&OUTER_SCHEMA, &o));
1283 assert_eq!(out, "<Outer><inner><name>v</name></inner></Outer>");
1284 }
1285
1286 #[test]
1287 fn xml_name_overrides_member_name() {
1288 static RENAMED_MEMBER: Schema<'static> = Schema::new_member(
1289 shape_id!("test", "Person$name"),
1290 ShapeType::String,
1291 "name",
1292 0,
1293 )
1294 .with_xml_name("FullName");
1295 static PERSON_SCHEMA: Schema<'static> = Schema::new_struct(
1296 shape_id!("test", "Person"),
1297 ShapeType::Structure,
1298 &[&RENAMED_MEMBER],
1299 );
1300
1301 struct P;
1302 impl SerializableStruct for P {
1303 fn schema(&self) -> &Schema<'_> {
1304 &PERSON_SCHEMA
1305 }
1306
1307 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1308 ser.write_string(&RENAMED_MEMBER, "v")
1309 }
1310 }
1311
1312 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &P));
1313 assert_eq!(out, "<Person><FullName>v</FullName></Person>");
1314 }
1315
1316 #[test]
1321 fn xml_name_and_namespace_from_a_runtime_schema() {
1322 let arena: Vec<String> = vec![
1324 String::from("name"), String::from("RuntimeFullName"), String::from("https://ns.example/"), ];
1328
1329 let member: Schema<'_> = Schema::new_member(
1330 shape_id!("test", "Person$name"),
1331 ShapeType::String,
1332 &arena[0],
1333 0,
1334 )
1335 .with_xml_name(&arena[1]);
1336
1337 let members = [&member];
1338 let person: Schema<'_> =
1339 Schema::new_struct(shape_id!("test", "Person"), ShapeType::Structure, &members)
1340 .with_xml_namespace(&arena[2], None);
1341
1342 struct P<'a> {
1343 schema: &'a Schema<'a>,
1344 member: &'a Schema<'a>,
1345 }
1346 impl SerializableStruct for P<'_> {
1347 fn schema(&self) -> &Schema<'_> {
1348 self.schema
1349 }
1350
1351 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1352 ser.write_string(self.member, "v")
1353 }
1354 }
1355 let value = P {
1356 schema: &person,
1357 member: &member,
1358 };
1359 let erased: &dyn SerializableStruct = &value;
1360 assert!(std::ptr::eq(erased.schema(), &person));
1361 let out = serialize(|ser| ser.write_struct(&person, erased));
1362 assert_eq!(
1363 out,
1364 "<Person xmlns=\"https://ns.example/\"><RuntimeFullName>v</RuntimeFullName></Person>"
1365 );
1366 }
1367
1368 #[test]
1369 fn original_name_overrides_id_for_synthetic_root() {
1370 static SYNTHETIC: Schema<'static> = Schema::new_struct(
1374 shape_id!("test.synthetic", "FooInput"),
1375 ShapeType::Structure,
1376 &[],
1377 )
1378 .with_original_name("FooRequest");
1379
1380 struct Empty;
1381 impl SerializableStruct for Empty {
1382 fn schema(&self) -> &Schema<'_> {
1383 &SYNTHETIC
1384 }
1385
1386 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1387 Ok(())
1388 }
1389 }
1390
1391 let out = serialize(|ser| ser.write_struct(&SYNTHETIC, &Empty));
1392 assert_eq!(out, "<FooRequest></FooRequest>");
1393 }
1394
1395 static SCALAR_MEMBER: Schema<'static> =
1398 Schema::new_member(shape_id!("test", "S$v"), ShapeType::Integer, "v", 0);
1399
1400 #[test]
1401 fn write_boolean_true() {
1402 let out = serialize(|ser| ser.write_boolean(&SCALAR_MEMBER, true));
1403 assert_eq!(out, "<v>true</v>");
1404 }
1405
1406 #[test]
1407 fn write_boolean_false() {
1408 let out = serialize(|ser| ser.write_boolean(&SCALAR_MEMBER, false));
1409 assert_eq!(out, "<v>false</v>");
1410 }
1411
1412 #[test]
1413 fn write_integer_negative() {
1414 let out = serialize(|ser| ser.write_integer(&SCALAR_MEMBER, -42));
1415 assert_eq!(out, "<v>-42</v>");
1416 }
1417
1418 #[test]
1419 fn write_long_large() {
1420 let out = serialize(|ser| ser.write_long(&SCALAR_MEMBER, i64::MAX));
1421 assert_eq!(out, format!("<v>{}</v>", i64::MAX));
1422 }
1423
1424 #[test]
1425 fn write_float_special_values() {
1426 let out = serialize(|ser| ser.write_float(&SCALAR_MEMBER, f32::NAN));
1427 assert_eq!(out, "<v>NaN</v>");
1428 let out = serialize(|ser| ser.write_float(&SCALAR_MEMBER, f32::INFINITY));
1429 assert_eq!(out, "<v>Infinity</v>");
1430 let out = serialize(|ser| ser.write_float(&SCALAR_MEMBER, f32::NEG_INFINITY));
1431 assert_eq!(out, "<v>-Infinity</v>");
1432 }
1433
1434 #[test]
1435 fn write_double_normal() {
1436 let out = serialize(|ser| ser.write_double(&SCALAR_MEMBER, 1.5));
1437 assert_eq!(out, "<v>1.5</v>");
1438 }
1439
1440 #[test]
1441 fn write_blob_base64() {
1442 let blob = Blob::new(b"hello");
1443 let out = serialize(|ser| ser.write_blob(&SCALAR_MEMBER, blob.clone()));
1444 assert_eq!(out, "<v>aGVsbG8=</v>");
1445 }
1446
1447 #[test]
1448 fn write_timestamp_default_datetime() {
1449 let ts = DateTime::from_secs(1515531081);
1451 let out = serialize(|ser| ser.write_timestamp(&SCALAR_MEMBER, &ts));
1452 assert_eq!(out, "<v>2018-01-09T20:51:21Z</v>");
1453 }
1454
1455 #[test]
1456 fn write_timestamp_epoch_seconds_override() {
1457 use aws_smithy_schema::traits::TimestampFormat as SchemaTimestampFormat;
1458 static TS_MEMBER: Schema<'static> =
1459 Schema::new_member(shape_id!("test", "S$t"), ShapeType::Timestamp, "t", 0)
1460 .with_timestamp_format(SchemaTimestampFormat::EpochSeconds);
1461 let ts = DateTime::from_secs(1515531081);
1462 let out = serialize(|ser| ser.write_timestamp(&TS_MEMBER, &ts));
1463 assert_eq!(out, "<t>1515531081</t>");
1464 }
1465
1466 #[test]
1467 fn write_null_emits_nothing() {
1468 let out = serialize(|ser| ser.write_null(&SCALAR_MEMBER));
1469 assert_eq!(out, "");
1470 }
1471
1472 #[test]
1475 fn attribute_string_on_struct() {
1476 static ATTR_MEMBER: Schema<'static> =
1477 Schema::new_member(shape_id!("test", "X$id"), ShapeType::String, "id", 0)
1478 .with_xml_attribute();
1479 static CHILD_MEMBER: Schema<'static> =
1480 Schema::new_member(shape_id!("test", "X$name"), ShapeType::String, "name", 1);
1481 static X_SCHEMA: Schema<'static> = Schema::new_struct(
1482 shape_id!("test", "X"),
1483 ShapeType::Structure,
1484 &[&ATTR_MEMBER, &CHILD_MEMBER],
1485 );
1486
1487 struct X;
1488 impl SerializableStruct for X {
1489 fn schema(&self) -> &Schema<'_> {
1490 &X_SCHEMA
1491 }
1492
1493 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1494 ser.write_string(&ATTR_MEMBER, "42")?;
1495 ser.write_string(&CHILD_MEMBER, "hello")
1496 }
1497 }
1498
1499 let out = serialize(|ser| ser.write_struct(&X_SCHEMA, &X));
1500 assert_eq!(out, "<X id=\"42\"><name>hello</name></X>");
1501 }
1502
1503 #[test]
1504 fn attribute_integer_on_struct() {
1505 static ATTR: Schema<'static> =
1506 Schema::new_member(shape_id!("test", "X$count"), ShapeType::Integer, "count", 0)
1507 .with_xml_attribute();
1508 static X_SCHEMA: Schema<'static> =
1509 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&ATTR]);
1510
1511 struct X;
1512 impl SerializableStruct for X {
1513 fn schema(&self) -> &Schema<'_> {
1514 &X_SCHEMA
1515 }
1516
1517 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1518 ser.write_integer(&ATTR, 7)
1519 }
1520 }
1521
1522 let out = serialize(|ser| ser.write_struct(&X_SCHEMA, &X));
1523 assert_eq!(out, "<X count=\"7\"></X>");
1524 }
1525
1526 #[test]
1527 fn attribute_value_is_escaped() {
1528 static ATTR: Schema<'static> =
1529 Schema::new_member(shape_id!("test", "X$v"), ShapeType::String, "v", 0)
1530 .with_xml_attribute();
1531 static X_SCHEMA: Schema<'static> =
1532 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&ATTR]);
1533
1534 struct X;
1535 impl SerializableStruct for X {
1536 fn schema(&self) -> &Schema<'_> {
1537 &X_SCHEMA
1538 }
1539
1540 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1541 ser.write_string(&ATTR, "a\"b&c")
1542 }
1543 }
1544
1545 let out = serialize(|ser| ser.write_struct(&X_SCHEMA, &X));
1546 assert_eq!(out, "<X v=\"a"b&c\"></X>");
1547 }
1548
1549 #[test]
1550 fn attribute_on_struct_returns_error() {
1551 static ATTR_STRUCT: Schema<'static> = Schema::new_member(
1552 shape_id!("test", "X$inner"),
1553 ShapeType::Structure,
1554 "inner",
1555 0,
1556 )
1557 .with_xml_attribute();
1558
1559 struct Empty;
1560 impl SerializableStruct for Empty {
1561 fn schema(&self) -> &Schema<'_> {
1562 &aws_smithy_schema::prelude::UNIT
1563 }
1564
1565 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1566 Ok(())
1567 }
1568 }
1569
1570 let mut ser = XmlSerializer::new(Arc::new(XmlCodecSettings::default()));
1571 let result = ser.write_struct(&ATTR_STRUCT, &Empty);
1572 assert!(result.is_err());
1573 }
1574
1575 #[test]
1578 fn namespace_on_struct() {
1579 static NS_SCHEMA: Schema<'static> =
1580 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[])
1581 .with_xml_namespace("https://example.com", None);
1582
1583 struct Empty;
1584 impl SerializableStruct for Empty {
1585 fn schema(&self) -> &Schema<'_> {
1586 &NS_SCHEMA
1587 }
1588
1589 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1590 Ok(())
1591 }
1592 }
1593
1594 let out = serialize(|ser| ser.write_struct(&NS_SCHEMA, &Empty));
1595 assert_eq!(out, "<X xmlns=\"https://example.com\"></X>");
1596 }
1597
1598 #[test]
1599 fn namespace_with_prefix() {
1600 static NS_SCHEMA: Schema<'static> =
1601 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[])
1602 .with_xml_namespace("https://example.com", Some("ex"));
1603
1604 struct Empty;
1605 impl SerializableStruct for Empty {
1606 fn schema(&self) -> &Schema<'_> {
1607 &NS_SCHEMA
1608 }
1609
1610 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1611 Ok(())
1612 }
1613 }
1614
1615 let out = serialize(|ser| ser.write_struct(&NS_SCHEMA, &Empty));
1616 assert_eq!(out, "<X xmlns:ex=\"https://example.com\"></X>");
1617 }
1618
1619 #[test]
1620 fn namespace_with_children() {
1621 static CHILD: Schema<'static> =
1622 Schema::new_member(shape_id!("test", "X$v"), ShapeType::String, "v", 0);
1623 static NS_SCHEMA: Schema<'static> =
1624 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&CHILD])
1625 .with_xml_namespace("urn:foo", None);
1626
1627 struct X;
1628 impl SerializableStruct for X {
1629 fn schema(&self) -> &Schema<'_> {
1630 &NS_SCHEMA
1631 }
1632
1633 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1634 ser.write_string(&CHILD, "hi")
1635 }
1636 }
1637
1638 let out = serialize(|ser| ser.write_struct(&NS_SCHEMA, &X));
1639 assert_eq!(out, "<X xmlns=\"urn:foo\"><v>hi</v></X>");
1640 }
1641
1642 #[test]
1645 fn list_wrapped() {
1646 static LIST_ITEM: Schema<'static> = Schema::new_member(
1649 shape_id!("test", "L$member"),
1650 ShapeType::String,
1651 "member",
1652 0,
1653 );
1654 static LIST_MEMBER: Schema<'static> =
1655 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0);
1656
1657 let out = serialize(|ser| {
1658 ser.write_list(&LIST_MEMBER, &|ser| {
1659 ser.write_string(&LIST_ITEM, "a")?;
1660 ser.write_string(&LIST_ITEM, "b")
1661 })
1662 });
1663 assert_eq!(out, "<items><member>a</member><member>b</member></items>");
1664 }
1665
1666 #[test]
1667 fn list_wrapped_with_xml_name_on_item() {
1668 static LIST_ITEM: Schema<'static> = Schema::new_member(
1670 shape_id!("test", "L$member"),
1671 ShapeType::String,
1672 "member",
1673 0,
1674 )
1675 .with_xml_name("Item");
1676 static LIST_MEMBER: Schema<'static> =
1677 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0);
1678
1679 let out = serialize(|ser| {
1680 ser.write_list(&LIST_MEMBER, &|ser| {
1681 ser.write_string(&LIST_ITEM, "a")?;
1682 ser.write_string(&LIST_ITEM, "b")
1683 })
1684 });
1685 assert_eq!(out, "<items><Item>a</Item><Item>b</Item></items>");
1686 }
1687
1688 #[test]
1689 fn list_flattened() {
1690 static LIST_ITEM: Schema<'static> = Schema::new_member(
1693 shape_id!("test", "L$member"),
1694 ShapeType::String,
1695 "member",
1696 0,
1697 )
1698 .with_xml_name("item");
1699 static LIST_MEMBER: Schema<'static> =
1700 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0)
1701 .with_xml_flattened();
1702
1703 let out = serialize(|ser| {
1704 ser.write_list(&LIST_MEMBER, &|ser| {
1705 ser.write_string(&LIST_ITEM, "a")?;
1706 ser.write_string(&LIST_ITEM, "b")
1707 })
1708 });
1709 assert_eq!(out, "<item>a</item><item>b</item>");
1711 }
1712
1713 #[test]
1716 fn map_wrapped() {
1717 static KEY_SCHEMA: Schema<'static> =
1718 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1719 static VALUE_SCHEMA: Schema<'static> =
1720 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
1721 static MAP_MEMBER: Schema<'static> =
1722 Schema::new_member(shape_id!("test", "S$myMap"), ShapeType::Map, "myMap", 0)
1723 .with_map_members(&KEY_SCHEMA, &VALUE_SCHEMA);
1724
1725 let out = serialize(|ser| {
1726 ser.write_map(&MAP_MEMBER, &|ser| {
1727 ser.write_string(&prelude::STRING, "k1")?;
1728 ser.write_string(&prelude::STRING, "v1")?;
1729 ser.write_string(&prelude::STRING, "k2")?;
1730 ser.write_string(&prelude::STRING, "v2")
1731 })
1732 });
1733 assert_eq!(
1734 out,
1735 "<myMap><entry><key>k1</key><value>v1</value></entry><entry><key>k2</key><value>v2</value></entry></myMap>"
1736 );
1737 }
1738
1739 #[test]
1740 fn map_wrapped_with_renamed_key_value() {
1741 static REN_KEY: Schema<'static> =
1743 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0)
1744 .with_xml_name("Attribute");
1745 static REN_VALUE: Schema<'static> =
1746 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1)
1747 .with_xml_name("Setting");
1748
1749 static MAP_MEMBER: Schema<'static> =
1750 Schema::new_member(shape_id!("test", "S$m"), ShapeType::Map, "m", 0)
1751 .with_map_members(&REN_KEY, &REN_VALUE);
1752
1753 let out = serialize(|ser| {
1754 ser.write_map(&MAP_MEMBER, &|ser| {
1755 ser.write_string(&prelude::STRING, "k")?;
1756 ser.write_string(&prelude::STRING, "v")
1757 })
1758 });
1759 assert_eq!(
1760 out,
1761 "<m><entry><Attribute>k</Attribute><Setting>v</Setting></entry></m>"
1762 );
1763 }
1764
1765 #[test]
1766 fn map_flattened() {
1767 static KEY_SCHEMA: Schema<'static> =
1768 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1769 static VALUE_SCHEMA: Schema<'static> =
1770 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
1771 static MAP_MEMBER: Schema<'static> =
1772 Schema::new_member(shape_id!("test", "S$m"), ShapeType::Map, "m", 0)
1773 .with_xml_flattened()
1774 .with_map_members(&KEY_SCHEMA, &VALUE_SCHEMA);
1775
1776 let out = serialize(|ser| {
1777 ser.write_map(&MAP_MEMBER, &|ser| {
1778 ser.write_string(&prelude::STRING, "a")?;
1779 ser.write_string(&prelude::STRING, "1")?;
1780 ser.write_string(&prelude::STRING, "b")?;
1781 ser.write_string(&prelude::STRING, "2")
1782 })
1783 });
1784 assert_eq!(
1786 out,
1787 "<m><key>a</key><value>1</value></m><m><key>b</key><value>2</value></m>"
1788 );
1789 }
1790
1791 #[test]
1792 fn write_document_returns_error() {
1793 let mut ser = XmlSerializer::new(Arc::new(XmlCodecSettings::default()));
1794 let result = ser.write_document(&SCALAR_MEMBER, &Document::Object(Default::default()));
1795 assert_eq!(
1796 result.unwrap_err().to_string(),
1797 "document types are not supported by REST XML"
1798 );
1799 }
1800
1801 #[test]
1802 fn map_with_struct_value() {
1803 static HI: Schema<'static> =
1804 Schema::new_member(shape_id!("test", "G$hi"), ShapeType::String, "hi", 0);
1805 static GREETING: Schema<'static> = Schema::new_struct(
1806 shape_id!("test", "GreetingStruct"),
1807 ShapeType::Structure,
1808 &[&HI],
1809 );
1810 static KEY: Schema<'static> =
1811 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1812 static VALUE: Schema<'static> =
1813 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
1814 static MAP: Schema<'static> =
1815 Schema::new_member(shape_id!("test", "S$myMap"), ShapeType::Map, "myMap", 0)
1816 .with_map_members(&KEY, &VALUE);
1817
1818 struct G;
1819 impl SerializableStruct for G {
1820 fn schema(&self) -> &Schema<'_> {
1821 &GREETING
1822 }
1823
1824 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1825 ser.write_string(&HI, "bye")
1826 }
1827 }
1828
1829 let out = serialize(|ser| {
1830 ser.write_map(&MAP, &|ser| {
1831 ser.write_string(&prelude::STRING, "baz")?;
1832 ser.write_struct(&GREETING, &G)
1833 })
1834 });
1835 assert_eq!(
1836 out,
1837 "<myMap><entry><key>baz</key><value><hi>bye</hi></value></entry></myMap>"
1838 );
1839 }
1840
1841 #[test]
1861 fn member_schema_struct_emits_attribute_member() {
1862 static ATTR_FIELD_MEMBER: Schema<'static> = Schema::new_member(
1864 shape_id!("test", "Inner$attrField"),
1865 ShapeType::String,
1866 "attrField",
1867 0,
1868 )
1869 .with_xml_name("xsi:someName")
1870 .with_xml_attribute();
1871 static INNER_TARGET: Schema<'static> = Schema::new_struct(
1872 shape_id!("test", "Inner"),
1873 ShapeType::Structure,
1874 &[&ATTR_FIELD_MEMBER],
1875 );
1876 static INNER_MEMBER: Schema<'static> = Schema::new_member(
1880 shape_id!("test", "Outer$nested"),
1881 ShapeType::Structure,
1882 "nested",
1883 0,
1884 );
1885 static OUTER_SCHEMA: Schema<'static> = Schema::new_struct(
1886 shape_id!("test", "Outer"),
1887 ShapeType::Structure,
1888 &[&INNER_MEMBER],
1889 );
1890
1891 struct Inner<'a> {
1892 attr: &'a str,
1893 }
1894 impl SerializableStruct for Inner<'_> {
1895 fn schema(&self) -> &Schema<'_> {
1896 &INNER_TARGET
1897 }
1898
1899 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1900 ser.write_string(&ATTR_FIELD_MEMBER, self.attr)
1901 }
1902 }
1903 struct Outer<'a> {
1904 inner: Inner<'a>,
1905 }
1906 impl SerializableStruct for Outer<'_> {
1907 fn schema(&self) -> &Schema<'_> {
1908 &OUTER_SCHEMA
1909 }
1910
1911 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1912 let _ = &INNER_TARGET;
1916 ser.write_struct(&INNER_MEMBER, &self.inner)
1917 }
1918 }
1919
1920 let outer = Outer {
1921 inner: Inner { attr: "v" },
1922 };
1923 let out = serialize(|ser| ser.write_struct(&OUTER_SCHEMA, &outer));
1924 assert_eq!(out, r#"<Outer><nested xsi:someName="v"></nested></Outer>"#);
1925 }
1926
1927 #[test]
1934 fn map_value_is_inner_map_with_renamed_inner_key_value() {
1935 static INNER_KEY: Schema<'static> = Schema::new_member(
1937 shape_id!("test", "InnerMap$key"),
1938 ShapeType::String,
1939 "key",
1940 0,
1941 )
1942 .with_xml_name("InnerKey");
1943 static INNER_VAL: Schema<'static> = Schema::new_member(
1944 shape_id!("test", "InnerMap$value"),
1945 ShapeType::String,
1946 "value",
1947 1,
1948 )
1949 .with_xml_name("InnerVal");
1950
1951 static OUTER_VALUE: Schema<'static> = Schema::new_member(
1956 shape_id!("test", "OuterMap$value"),
1957 ShapeType::Map,
1958 "value",
1959 1,
1960 )
1961 .with_map_members(&INNER_KEY, &INNER_VAL);
1962
1963 static OUTER_KEY: Schema<'static> = Schema::new_member(
1965 shape_id!("test", "OuterMap$key"),
1966 ShapeType::String,
1967 "key",
1968 0,
1969 );
1970 static OUTER_MAP: Schema<'static> = Schema::new_member(
1971 shape_id!("test", "S$outerMap"),
1972 ShapeType::Map,
1973 "outerMap",
1974 0,
1975 )
1976 .with_map_members(&OUTER_KEY, &OUTER_VALUE);
1977
1978 let out = serialize(|ser| {
1979 ser.write_map(&OUTER_MAP, &|ser| {
1980 ser.write_string(&prelude::STRING, "ok")?;
1981 ser.write_map(&OUTER_VALUE, &|ser| {
1984 ser.write_string(&prelude::STRING, "ik")?;
1985 ser.write_string(&prelude::STRING, "iv")
1986 })
1987 })
1988 });
1989
1990 assert_eq!(
1991 out,
1992 "<outerMap><entry><key>ok</key><value><entry><InnerKey>ik</InnerKey><InnerVal>iv</InnerVal></entry></value></entry></outerMap>"
1993 );
1994 }
1995
1996 #[test]
2000 fn list_member_is_inner_map_with_renamed_inner_key_value() {
2001 static INNER_KEY: Schema<'static> = Schema::new_member(
2002 shape_id!("test", "InnerMap$key"),
2003 ShapeType::String,
2004 "key",
2005 0,
2006 )
2007 .with_xml_name("Attr");
2008 static INNER_VAL: Schema<'static> = Schema::new_member(
2009 shape_id!("test", "InnerMap$value"),
2010 ShapeType::String,
2011 "value",
2012 1,
2013 )
2014 .with_xml_name("Set");
2015
2016 static LIST_ITEM: Schema<'static> = Schema::new_member(
2018 shape_id!("test", "OuterList$member"),
2019 ShapeType::Map,
2020 "member",
2021 0,
2022 )
2023 .with_map_members(&INNER_KEY, &INNER_VAL);
2024
2025 static OUTER_LIST: Schema<'static> =
2026 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0)
2027 .with_list_member(&LIST_ITEM);
2028
2029 let out = serialize(|ser| {
2030 ser.write_list(&OUTER_LIST, &|ser| {
2031 ser.write_map(&LIST_ITEM, &|ser| {
2033 ser.write_string(&prelude::STRING, "k1")?;
2034 ser.write_string(&prelude::STRING, "v1")
2035 })
2036 })
2037 });
2038
2039 assert_eq!(
2043 out,
2044 "<items><member><entry><Attr>k1</Attr><Set>v1</Set></entry></member></items>"
2045 );
2046 }
2047
2048 static CD_ENABLED_X: Schema<'static> = Schema::new_member(
2053 shape_id!("test", "ConnectionDraining$enabled"),
2054 ShapeType::Boolean,
2055 "enabled",
2056 0,
2057 );
2058 static LBA_CD_X: Schema<'static> = Schema::new_member(
2059 shape_id!("test", "LoadBalancerAttributes$connectionDraining"),
2060 ShapeType::Structure,
2061 "connectionDraining",
2062 0,
2063 );
2064 static LBA_SCHEMA_X: Schema<'static> = Schema::new_struct(
2065 shape_id!("test", "LoadBalancerAttributes"),
2066 ShapeType::Structure,
2067 &[&LBA_CD_X],
2068 );
2069
2070 struct ConnectionDrainingX {
2071 enabled: bool,
2072 }
2073 impl SerializableStruct for ConnectionDrainingX {
2074 fn schema(&self) -> &Schema<'_> {
2075 static SCHEMA: Schema<'static> = Schema::new_struct(
2076 aws_smithy_schema::shape_id!("test", "ConnectionDraining"),
2077 aws_smithy_schema::ShapeType::Structure,
2078 &[&CD_ENABLED_X],
2079 );
2080 &SCHEMA
2081 }
2082
2083 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
2084 let val = &self.enabled;
2085 ser.write_boolean(&CD_ENABLED_X, *val)
2086 }
2087 }
2088 struct LoadBalancerAttributesX {
2089 connection_draining: ConnectionDrainingX,
2090 }
2091 impl SerializableStruct for LoadBalancerAttributesX {
2092 fn schema(&self) -> &Schema<'_> {
2093 &LBA_SCHEMA_X
2094 }
2095
2096 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
2097 ser.write_struct(&LBA_CD_X, &self.connection_draining)
2098 }
2099 }
2100
2101 #[test]
2102 fn required_value_type_false_bool_is_serialized() {
2103 let out = serialize(|ser| {
2104 ser.write_struct(
2105 &LBA_SCHEMA_X,
2106 &LoadBalancerAttributesX {
2107 connection_draining: ConnectionDrainingX { enabled: false },
2108 },
2109 )
2110 });
2111 assert_eq!(
2112 out,
2113 "<LoadBalancerAttributes><connectionDraining><enabled>false</enabled></connectionDraining></LoadBalancerAttributes>",
2114 "the required-default value-type member must be present with false, not dropped"
2115 );
2116 }
2117
2118 #[test]
2123 fn cached_names_do_not_capture_names_from_an_enclosing_list() {
2124 static ROW: Schema<'static> = Schema::new_member(
2125 shape_id!("test", "Rows$member"),
2126 ShapeType::List,
2127 "member",
2128 0,
2129 )
2130 .with_xml_name("Row");
2131 static ROWS: Schema<'static> =
2132 Schema::new_member(shape_id!("test", "S$rows"), ShapeType::List, "rows", 0)
2133 .with_list_member(&ROW);
2134 static COL: Schema<'static> = Schema::new_member(
2135 shape_id!("test", "Cols$member"),
2136 ShapeType::List,
2137 "member",
2138 0,
2139 )
2140 .with_xml_name("Col");
2141 static COLS: Schema<'static> =
2142 Schema::new_member(shape_id!("test", "S$cols"), ShapeType::List, "cols", 1)
2143 .with_list_member(&COL);
2144
2145 let nested = |outer: &'static Schema<'static>| {
2146 serialize(move |ser| {
2147 ser.write_list(outer, &|ser| {
2148 ser.write_list(&prelude::DOCUMENT, &|ser| {
2149 ser.write_string(&prelude::STRING, "a")
2150 })
2151 })
2152 })
2153 };
2154 for _ in 0..2 {
2155 assert_eq!(nested(&ROWS), "<rows><Row><member>a</member></Row></rows>");
2156 assert_eq!(nested(&COLS), "<cols><Col><member>a</member></Col></cols>");
2157 }
2158 }
2159
2160 #[test]
2164 fn flattened_list_item_name_follows_the_enclosing_list() {
2165 static FLAT: Schema<'static> =
2166 Schema::new_member(shape_id!("test", "S$flat"), ShapeType::List, "flat", 0)
2167 .with_xml_flattened();
2168 static OUTER_ITEM: Schema<'static> = Schema::new_member(
2169 shape_id!("test", "Outer$member"),
2170 ShapeType::List,
2171 "member",
2172 0,
2173 )
2174 .with_xml_name("Inherited");
2175 static OUTER: Schema<'static> =
2176 Schema::new_member(shape_id!("test", "S$outer"), ShapeType::List, "outer", 0)
2177 .with_list_member(&OUTER_ITEM);
2178
2179 let flat = || {
2180 serialize(|ser| ser.write_list(&FLAT, &|ser| ser.write_string(&prelude::STRING, "x")))
2181 };
2182 let inherited = || {
2183 serialize(|ser| {
2184 ser.write_list(&OUTER, &|ser| {
2185 ser.write_list(&FLAT, &|ser| ser.write_string(&prelude::STRING, "x"))
2186 })
2187 })
2188 };
2189 for _ in 0..2 {
2190 assert_eq!(flat(), "<flat>x</flat>");
2191 assert_eq!(inherited(), "<outer><Inherited>x</Inherited></outer>");
2192 }
2193 }
2194
2195 #[test]
2198 fn cached_namespaces_are_written_on_every_request() {
2199 static ITEM: Schema<'static> = Schema::new_member(
2200 shape_id!("test", "L$member"),
2201 ShapeType::String,
2202 "member",
2203 0,
2204 )
2205 .with_xml_namespace("urn:item", Some("i"));
2206 static LIST: Schema<'static> =
2207 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0)
2208 .with_list_member(&ITEM);
2209 static KEY: Schema<'static> =
2210 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0)
2211 .with_xml_name("K")
2212 .with_xml_namespace("urn:key", None);
2213 static VALUE: Schema<'static> =
2214 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1)
2215 .with_xml_namespace("urn:value", Some("v"));
2216 static MAP: Schema<'static> =
2217 Schema::new_member(shape_id!("test", "S$m"), ShapeType::Map, "m", 1)
2218 .with_map_members(&KEY, &VALUE);
2219
2220 for _ in 0..2 {
2221 let list = serialize(|ser| {
2222 ser.write_list(&LIST, &|ser| {
2223 ser.write_string(&prelude::STRING, "a")?;
2224 ser.write_integer(&prelude::INTEGER, 1)
2225 })
2226 });
2227 assert_eq!(
2228 list,
2229 "<items><member xmlns:i=\"urn:item\">a</member><member xmlns:i=\"urn:item\">1</member></items>"
2230 );
2231 let map = serialize(|ser| {
2232 ser.write_map(&MAP, &|ser| {
2233 ser.write_string(&prelude::STRING, "k")?;
2234 ser.write_string(&prelude::STRING, "v")
2235 })
2236 });
2237 assert_eq!(
2238 map,
2239 "<m><entry><K xmlns=\"urn:key\">k</K><value xmlns:v=\"urn:value\">v</value></entry></m>"
2240 );
2241 }
2242 }
2243}