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()
586 } else {
587 None
588 };
589 let mut inherited_name = None;
590 let name = match &root_override {
591 Some(override_name) => override_name.as_str(),
592 None => self.resolve_name(schema, &mut inherited_name),
593 };
594 let saved_list_item = self.list_item_name.take();
595 self.open_element(name);
596 self.write_xmlns(schema, None);
597 let saved_filter = self.member_filter;
615 let has_attrs = schema.member_name().is_some()
616 || schema.members().iter().any(|m| m.xml_attribute());
617 if has_attrs {
618 self.member_filter = MemberFilter::AttributesOnly;
619 value.serialize_members(self)?;
620 }
621 self.member_filter = MemberFilter::NonAttributesOnly;
622 value.serialize_members(self)?;
623 self.member_filter = saved_filter;
624 self.close_element(name);
625 self.list_item_name = saved_list_item;
626 }
627 Ok(())
628 }
629
630 fn write_list(
631 &mut self,
632 schema: &Schema<'_>,
633 write_elements: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
634 ) -> Result<(), SerdeError> {
635 if schema.xml_attribute() {
636 return Err(SerdeError::custom(
637 "@xmlAttribute is not supported on aggregate types",
638 ));
639 }
640 if !self.filter_allows(schema) {
641 return Ok(());
642 }
643
644 self.flush_start_tag();
645
646 let in_map_value = if let Some(map_state) = &mut self.map_state {
648 if !map_state.expecting_key {
649 use std::fmt::Write;
650 write!(self.output, "<{}>", map_state.value_name).unwrap();
651 map_state.expecting_key = true;
652 true
653 } else {
654 false
655 }
656 } else {
657 false
658 };
659 let saved_map_state = if in_map_value {
660 self.map_state.take()
661 } else {
662 None
663 };
664
665 let names = schema.extension(&XML_LIST_NAMES);
675 let item_name = if schema.xml_flattened() && schema.xml_name().is_none() {
676 self.list_item_name
678 .clone()
679 .unwrap_or_else(|| names.item.clone())
680 } else {
681 names.item.clone()
682 };
683 let mut inherited_name = None;
691 let wrapper_name = self.resolve_name(schema, &mut inherited_name);
692
693 let saved_list_item = self.list_item_name.take();
694 self.list_item_name = Some(item_name);
695
696 let saved_list_item_ns =
702 std::mem::replace(&mut self.list_item_namespace, names.item_namespace.clone());
703
704 if schema.xml_flattened() || in_map_value {
705 write_elements(self)?;
706 } else {
707 self.open_element(wrapper_name);
708 self.write_xmlns(schema, None);
711 write_elements(self)?;
712 self.close_element(wrapper_name);
713 }
714
715 self.list_item_name = saved_list_item;
716 self.list_item_namespace = saved_list_item_ns;
717
718 if in_map_value {
719 use std::fmt::Write;
720 let saved = saved_map_state.as_ref().unwrap();
721 let val_name = &saved.value_name;
722 let entry = &saved.entry_name;
723 write!(self.output, "</{val_name}></{entry}>").unwrap();
724 self.map_state = saved_map_state;
725 }
726 Ok(())
727 }
728
729 fn write_map(
730 &mut self,
731 schema: &Schema<'_>,
732 write_entries: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
733 ) -> Result<(), SerdeError> {
734 if schema.xml_attribute() {
735 return Err(SerdeError::custom(
736 "@xmlAttribute is not supported on aggregate types",
737 ));
738 }
739 if !self.filter_allows(schema) {
740 return Ok(());
741 }
742
743 self.flush_start_tag();
744
745 let in_map_value = if let Some(map_state) = &mut self.map_state {
747 if !map_state.expecting_key {
748 use std::fmt::Write;
749 write!(self.output, "<{}>", map_state.value_name).unwrap();
750 map_state.expecting_key = true;
751 true
752 } else {
753 false
754 }
755 } else {
756 false
757 };
758
759 let outer_map_state = self.map_state.take();
760
761 let names = schema.extension(&XML_MAP_NAMES);
763 self.map_state = Some(MapState {
764 entry_name: names.entry.clone(),
765 key_name: names.key.clone(),
766 value_name: names.value.clone(),
767 key_namespace: names.key_namespace.clone(),
768 value_namespace: names.value_namespace.clone(),
769 expecting_key: true,
770 });
771
772 let mut inherited_name = None;
779 let wrapper_name = self.resolve_name(schema, &mut inherited_name);
780
781 let saved_list_item = self.list_item_name.take();
784
785 if schema.xml_flattened() || in_map_value {
786 write_entries(self)?;
787 } else {
788 self.open_element(wrapper_name);
789 self.write_xmlns(schema, None);
790 write_entries(self)?;
791 self.close_element(wrapper_name);
792 }
793
794 self.list_item_name = saved_list_item;
795
796 self.map_state = outer_map_state;
797
798 if in_map_value {
799 use std::fmt::Write;
800 let saved = self.map_state.as_ref().unwrap();
801 let val_name = &saved.value_name;
802 let entry = &saved.entry_name;
803 write!(self.output, "</{val_name}></{entry}>").unwrap();
804 }
805 Ok(())
806 }
807
808 fn write_boolean(&mut self, schema: &Schema<'_>, value: bool) -> Result<(), SerdeError> {
809 self.write_safe_element(schema, if value { "true" } else { "false" });
810 Ok(())
811 }
812
813 fn write_byte(&mut self, schema: &Schema<'_>, value: i8) -> Result<(), SerdeError> {
814 self.write_safe_element(schema, &value.to_string());
815 Ok(())
816 }
817
818 fn write_short(&mut self, schema: &Schema<'_>, value: i16) -> Result<(), SerdeError> {
819 self.write_safe_element(schema, &value.to_string());
820 Ok(())
821 }
822
823 fn write_integer(&mut self, schema: &Schema<'_>, value: i32) -> Result<(), SerdeError> {
824 self.write_safe_element(schema, &value.to_string());
825 Ok(())
826 }
827
828 fn write_long(&mut self, schema: &Schema<'_>, value: i64) -> Result<(), SerdeError> {
829 self.write_safe_element(schema, &value.to_string());
830 Ok(())
831 }
832
833 fn write_float(&mut self, schema: &Schema<'_>, value: f32) -> Result<(), SerdeError> {
834 let text = if value.is_nan() {
835 "NaN".to_owned()
836 } else if value.is_infinite() {
837 if value.is_sign_positive() {
838 "Infinity".to_owned()
839 } else {
840 "-Infinity".to_owned()
841 }
842 } else {
843 value.to_string()
844 };
845 self.write_safe_element(schema, &text);
846 Ok(())
847 }
848
849 fn write_double(&mut self, schema: &Schema<'_>, value: f64) -> Result<(), SerdeError> {
850 let text = if value.is_nan() {
851 "NaN".to_owned()
852 } else if value.is_infinite() {
853 if value.is_sign_positive() {
854 "Infinity".to_owned()
855 } else {
856 "-Infinity".to_owned()
857 }
858 } else {
859 value.to_string()
860 };
861 self.write_safe_element(schema, &text);
862 Ok(())
863 }
864
865 fn write_big_integer(
866 &mut self,
867 schema: &Schema<'_>,
868 value: &BigInteger,
869 ) -> Result<(), SerdeError> {
870 self.write_safe_element(schema, value.as_ref());
871 Ok(())
872 }
873
874 fn write_big_decimal(
875 &mut self,
876 schema: &Schema<'_>,
877 value: &BigDecimal,
878 ) -> Result<(), SerdeError> {
879 self.write_safe_element(schema, value.as_ref());
880 Ok(())
881 }
882
883 fn write_string(&mut self, schema: &Schema<'_>, value: &str) -> Result<(), SerdeError> {
884 if !self.filter_allows(schema) {
885 return Ok(());
886 }
887 if self.try_write_attribute(schema, value) {
888 return Ok(());
889 }
890 use std::fmt::Write;
891 self.flush_start_tag();
892 let escaped = crate::escape::escape(value);
893 if let Some(map_state) = &mut self.map_state {
894 if map_state.expecting_key {
895 let (entry, key) = (&map_state.entry_name, &map_state.key_name);
896 write!(self.output, "<{entry}><{key}").unwrap();
897 write_xmlns_attr(&mut self.output, map_state.key_namespace.as_deref());
898 write!(self.output, ">{escaped}</{key}>").unwrap();
899 map_state.expecting_key = false;
900 } else {
901 let (entry, val_name) = (&map_state.entry_name, &map_state.value_name);
902 write!(self.output, "<{val_name}").unwrap();
903 write_xmlns_attr(&mut self.output, map_state.value_namespace.as_deref());
904 write!(self.output, ">{escaped}</{val_name}></{entry}>").unwrap();
905 map_state.expecting_key = true;
906 }
907 } else {
908 let mut inherited_name = None;
909 let name = self.resolve_name(schema, &mut inherited_name);
910 self.open_element(name);
913 let inherited = self.list_item_namespace.clone();
914 self.write_xmlns(schema, inherited.as_deref());
915 self.flush_start_tag();
916 self.output.push_str(&escaped);
917 self.close_element(name);
918 }
919 Ok(())
920 }
921
922 fn write_blob(
923 &mut self,
924 schema: &Schema<'_>,
925 value: aws_smithy_types::Blob,
926 ) -> Result<(), SerdeError> {
927 let encoded = aws_smithy_types::base64::encode(value.as_ref());
928 self.write_safe_element(schema, &encoded);
929 Ok(())
930 }
931
932 fn write_timestamp(&mut self, schema: &Schema<'_>, value: &DateTime) -> Result<(), SerdeError> {
933 let format = self.resolve_timestamp_format(schema)?;
934 let formatted = value
935 .fmt(format)
936 .map_err(|e| SerdeError::custom(e.to_string()))?;
937 self.write_safe_element(schema, &formatted);
939 Ok(())
940 }
941
942 fn write_document(
943 &mut self,
944 _schema: &Schema<'_>,
945 _value: &Document,
946 ) -> Result<(), SerdeError> {
947 Err(SerdeError::custom(
948 "document types are not supported by REST XML",
949 ))
950 }
951
952 fn write_null(&mut self, _schema: &Schema<'_>) -> Result<(), SerdeError> {
953 Ok(())
957 }
958}
959
960#[cfg(test)]
961mod tests {
962 use super::*;
963 use aws_smithy_schema::{prelude, shape_id, Schema, ShapeType};
964 use aws_smithy_types::Blob;
965
966 static NAME_MEMBER: Schema<'static> = Schema::new_member(
968 shape_id!("test", "Person$name"),
969 ShapeType::String,
970 "name",
971 0,
972 );
973 static PERSON_SCHEMA: Schema<'static> = Schema::new_struct(
974 shape_id!("test", "Person"),
975 ShapeType::Structure,
976 &[&NAME_MEMBER],
977 );
978
979 struct Person<'a> {
980 name: &'a str,
981 }
982
983 impl SerializableStruct for Person<'_> {
984 fn schema(&self) -> &Schema<'_> {
985 &PERSON_SCHEMA
986 }
987
988 fn serialize_members(
989 &self,
990 serializer: &mut dyn ShapeSerializer,
991 ) -> Result<(), SerdeError> {
992 serializer.write_string(&NAME_MEMBER, self.name)
993 }
994 }
995
996 fn serialize<F>(write: F) -> String
997 where
998 F: FnOnce(&mut XmlSerializer) -> Result<(), SerdeError>,
999 {
1000 let mut ser = XmlSerializer::new(Arc::new(XmlCodecSettings::default()));
1001 write(&mut ser).expect("serialization failed");
1002 String::from_utf8(<XmlSerializer as FinishSerializer>::finish(ser)).unwrap()
1003 }
1004
1005 #[test]
1006 fn struct_with_string_member() {
1007 let p = Person { name: "Iago" };
1008 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &p));
1009 assert_eq!(out, "<Person><name>Iago</name></Person>");
1010 }
1011
1012 #[test]
1013 fn struct_with_no_members_self_closes() {
1014 struct Empty;
1015 impl SerializableStruct for Empty {
1016 fn schema(&self) -> &Schema<'_> {
1017 &EMPTY_SCHEMA
1018 }
1019
1020 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1021 Ok(())
1022 }
1023 }
1024 static EMPTY_SCHEMA: Schema<'static> =
1025 Schema::new_struct(shape_id!("test", "Empty"), ShapeType::Structure, &[]);
1026
1027 let out = serialize(|ser| ser.write_struct(&EMPTY_SCHEMA, &Empty));
1028 assert_eq!(out, "<Empty></Empty>");
1029 }
1030
1031 #[test]
1032 fn struct_string_value_is_escaped() {
1033 let p = Person { name: "<a&b>" };
1034 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &p));
1035 assert_eq!(out, "<Person><name><a&b></name></Person>");
1036 }
1037
1038 #[test]
1039 fn struct_string_value_eol_is_encoded() {
1040 let p = Person { name: "a\r\nb" };
1043 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &p));
1044 assert_eq!(out, "<Person><name>a
b</name></Person>");
1045 }
1046
1047 #[test]
1048 fn nested_structs_close_correctly() {
1049 static INNER_NAME: Schema<'static> = Schema::new_member(
1055 shape_id!("test", "Inner$name"),
1056 ShapeType::String,
1057 "name",
1058 0,
1059 );
1060 static OUTER_INNER: Schema<'static> = Schema::new_member(
1061 shape_id!("test", "Outer$inner"),
1062 ShapeType::Structure,
1063 "inner",
1064 0,
1065 );
1066 static OUTER_SCHEMA: Schema<'static> = Schema::new_struct(
1067 shape_id!("test", "Outer"),
1068 ShapeType::Structure,
1069 &[&OUTER_INNER],
1070 );
1071
1072 struct Inner<'a> {
1073 name: &'a str,
1074 }
1075 impl SerializableStruct for Inner<'_> {
1076 fn schema(&self) -> &Schema<'_> {
1077 static SCHEMA: Schema<'static> = Schema::new_struct(
1078 aws_smithy_schema::shape_id!("test", "Inner"),
1079 aws_smithy_schema::ShapeType::Structure,
1080 &[&INNER_NAME],
1081 );
1082 &SCHEMA
1083 }
1084
1085 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1086 ser.write_string(&INNER_NAME, self.name)
1087 }
1088 }
1089 struct Outer<'a> {
1090 inner: Inner<'a>,
1091 }
1092 impl SerializableStruct for Outer<'_> {
1093 fn schema(&self) -> &Schema<'_> {
1094 &OUTER_SCHEMA
1095 }
1096
1097 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1098 ser.write_struct(&OUTER_INNER, &self.inner)
1102 }
1103 }
1104
1105 let o = Outer {
1106 inner: Inner { name: "v" },
1107 };
1108 let out = serialize(|ser| ser.write_struct(&OUTER_SCHEMA, &o));
1109 assert_eq!(out, "<Outer><inner><name>v</name></inner></Outer>");
1110 }
1111
1112 #[test]
1113 fn xml_name_overrides_member_name() {
1114 static RENAMED_MEMBER: Schema<'static> = Schema::new_member(
1115 shape_id!("test", "Person$name"),
1116 ShapeType::String,
1117 "name",
1118 0,
1119 )
1120 .with_xml_name("FullName");
1121 static PERSON_SCHEMA: Schema<'static> = Schema::new_struct(
1122 shape_id!("test", "Person"),
1123 ShapeType::Structure,
1124 &[&RENAMED_MEMBER],
1125 );
1126
1127 struct P;
1128 impl SerializableStruct for P {
1129 fn schema(&self) -> &Schema<'_> {
1130 &PERSON_SCHEMA
1131 }
1132
1133 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1134 ser.write_string(&RENAMED_MEMBER, "v")
1135 }
1136 }
1137
1138 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &P));
1139 assert_eq!(out, "<Person><FullName>v</FullName></Person>");
1140 }
1141
1142 #[test]
1147 fn xml_name_and_namespace_from_a_runtime_schema() {
1148 let arena: Vec<String> = vec![
1150 String::from("name"), String::from("RuntimeFullName"), String::from("https://ns.example/"), ];
1154
1155 let member: Schema<'_> = Schema::new_member(
1156 shape_id!("test", "Person$name"),
1157 ShapeType::String,
1158 &arena[0],
1159 0,
1160 )
1161 .with_xml_name(&arena[1]);
1162
1163 let members = [&member];
1164 let person: Schema<'_> =
1165 Schema::new_struct(shape_id!("test", "Person"), ShapeType::Structure, &members)
1166 .with_xml_namespace(&arena[2], None);
1167
1168 struct P<'a> {
1169 schema: &'a Schema<'a>,
1170 member: &'a Schema<'a>,
1171 }
1172 impl SerializableStruct for P<'_> {
1173 fn schema(&self) -> &Schema<'_> {
1174 self.schema
1175 }
1176
1177 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1178 ser.write_string(self.member, "v")
1179 }
1180 }
1181 let value = P {
1182 schema: &person,
1183 member: &member,
1184 };
1185 let erased: &dyn SerializableStruct = &value;
1186 assert!(std::ptr::eq(erased.schema(), &person));
1187 let out = serialize(|ser| ser.write_struct(&person, erased));
1188 assert_eq!(
1189 out,
1190 "<Person xmlns=\"https://ns.example/\"><RuntimeFullName>v</RuntimeFullName></Person>"
1191 );
1192 }
1193
1194 #[test]
1195 fn original_name_overrides_id_for_synthetic_root() {
1196 static SYNTHETIC: Schema<'static> = Schema::new_struct(
1200 shape_id!("test.synthetic", "FooInput"),
1201 ShapeType::Structure,
1202 &[],
1203 )
1204 .with_original_name("FooRequest");
1205
1206 struct Empty;
1207 impl SerializableStruct for Empty {
1208 fn schema(&self) -> &Schema<'_> {
1209 &SYNTHETIC
1210 }
1211
1212 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1213 Ok(())
1214 }
1215 }
1216
1217 let out = serialize(|ser| ser.write_struct(&SYNTHETIC, &Empty));
1218 assert_eq!(out, "<FooRequest></FooRequest>");
1219 }
1220
1221 static SCALAR_MEMBER: Schema<'static> =
1224 Schema::new_member(shape_id!("test", "S$v"), ShapeType::Integer, "v", 0);
1225
1226 #[test]
1227 fn write_boolean_true() {
1228 let out = serialize(|ser| ser.write_boolean(&SCALAR_MEMBER, true));
1229 assert_eq!(out, "<v>true</v>");
1230 }
1231
1232 #[test]
1233 fn write_boolean_false() {
1234 let out = serialize(|ser| ser.write_boolean(&SCALAR_MEMBER, false));
1235 assert_eq!(out, "<v>false</v>");
1236 }
1237
1238 #[test]
1239 fn write_integer_negative() {
1240 let out = serialize(|ser| ser.write_integer(&SCALAR_MEMBER, -42));
1241 assert_eq!(out, "<v>-42</v>");
1242 }
1243
1244 #[test]
1245 fn write_long_large() {
1246 let out = serialize(|ser| ser.write_long(&SCALAR_MEMBER, i64::MAX));
1247 assert_eq!(out, format!("<v>{}</v>", i64::MAX));
1248 }
1249
1250 #[test]
1251 fn write_float_special_values() {
1252 let out = serialize(|ser| ser.write_float(&SCALAR_MEMBER, f32::NAN));
1253 assert_eq!(out, "<v>NaN</v>");
1254 let out = serialize(|ser| ser.write_float(&SCALAR_MEMBER, f32::INFINITY));
1255 assert_eq!(out, "<v>Infinity</v>");
1256 let out = serialize(|ser| ser.write_float(&SCALAR_MEMBER, f32::NEG_INFINITY));
1257 assert_eq!(out, "<v>-Infinity</v>");
1258 }
1259
1260 #[test]
1261 fn write_double_normal() {
1262 let out = serialize(|ser| ser.write_double(&SCALAR_MEMBER, 1.5));
1263 assert_eq!(out, "<v>1.5</v>");
1264 }
1265
1266 #[test]
1267 fn write_blob_base64() {
1268 let blob = Blob::new(b"hello");
1269 let out = serialize(|ser| ser.write_blob(&SCALAR_MEMBER, blob.clone()));
1270 assert_eq!(out, "<v>aGVsbG8=</v>");
1271 }
1272
1273 #[test]
1274 fn write_timestamp_default_datetime() {
1275 let ts = DateTime::from_secs(1515531081);
1277 let out = serialize(|ser| ser.write_timestamp(&SCALAR_MEMBER, &ts));
1278 assert_eq!(out, "<v>2018-01-09T20:51:21Z</v>");
1279 }
1280
1281 #[test]
1282 fn write_timestamp_epoch_seconds_override() {
1283 use aws_smithy_schema::traits::TimestampFormat as SchemaTimestampFormat;
1284 static TS_MEMBER: Schema<'static> =
1285 Schema::new_member(shape_id!("test", "S$t"), ShapeType::Timestamp, "t", 0)
1286 .with_timestamp_format(SchemaTimestampFormat::EpochSeconds);
1287 let ts = DateTime::from_secs(1515531081);
1288 let out = serialize(|ser| ser.write_timestamp(&TS_MEMBER, &ts));
1289 assert_eq!(out, "<t>1515531081</t>");
1290 }
1291
1292 #[test]
1293 fn write_null_emits_nothing() {
1294 let out = serialize(|ser| ser.write_null(&SCALAR_MEMBER));
1295 assert_eq!(out, "");
1296 }
1297
1298 #[test]
1301 fn attribute_string_on_struct() {
1302 static ATTR_MEMBER: Schema<'static> =
1303 Schema::new_member(shape_id!("test", "X$id"), ShapeType::String, "id", 0)
1304 .with_xml_attribute();
1305 static CHILD_MEMBER: Schema<'static> =
1306 Schema::new_member(shape_id!("test", "X$name"), ShapeType::String, "name", 1);
1307 static X_SCHEMA: Schema<'static> = Schema::new_struct(
1308 shape_id!("test", "X"),
1309 ShapeType::Structure,
1310 &[&ATTR_MEMBER, &CHILD_MEMBER],
1311 );
1312
1313 struct X;
1314 impl SerializableStruct for X {
1315 fn schema(&self) -> &Schema<'_> {
1316 &X_SCHEMA
1317 }
1318
1319 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1320 ser.write_string(&ATTR_MEMBER, "42")?;
1321 ser.write_string(&CHILD_MEMBER, "hello")
1322 }
1323 }
1324
1325 let out = serialize(|ser| ser.write_struct(&X_SCHEMA, &X));
1326 assert_eq!(out, "<X id=\"42\"><name>hello</name></X>");
1327 }
1328
1329 #[test]
1330 fn attribute_integer_on_struct() {
1331 static ATTR: Schema<'static> =
1332 Schema::new_member(shape_id!("test", "X$count"), ShapeType::Integer, "count", 0)
1333 .with_xml_attribute();
1334 static X_SCHEMA: Schema<'static> =
1335 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&ATTR]);
1336
1337 struct X;
1338 impl SerializableStruct for X {
1339 fn schema(&self) -> &Schema<'_> {
1340 &X_SCHEMA
1341 }
1342
1343 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1344 ser.write_integer(&ATTR, 7)
1345 }
1346 }
1347
1348 let out = serialize(|ser| ser.write_struct(&X_SCHEMA, &X));
1349 assert_eq!(out, "<X count=\"7\"></X>");
1350 }
1351
1352 #[test]
1353 fn attribute_value_is_escaped() {
1354 static ATTR: Schema<'static> =
1355 Schema::new_member(shape_id!("test", "X$v"), ShapeType::String, "v", 0)
1356 .with_xml_attribute();
1357 static X_SCHEMA: Schema<'static> =
1358 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&ATTR]);
1359
1360 struct X;
1361 impl SerializableStruct for X {
1362 fn schema(&self) -> &Schema<'_> {
1363 &X_SCHEMA
1364 }
1365
1366 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1367 ser.write_string(&ATTR, "a\"b&c")
1368 }
1369 }
1370
1371 let out = serialize(|ser| ser.write_struct(&X_SCHEMA, &X));
1372 assert_eq!(out, "<X v=\"a"b&c\"></X>");
1373 }
1374
1375 #[test]
1376 fn attribute_on_struct_returns_error() {
1377 static ATTR_STRUCT: Schema<'static> = Schema::new_member(
1378 shape_id!("test", "X$inner"),
1379 ShapeType::Structure,
1380 "inner",
1381 0,
1382 )
1383 .with_xml_attribute();
1384
1385 struct Empty;
1386 impl SerializableStruct for Empty {
1387 fn schema(&self) -> &Schema<'_> {
1388 &aws_smithy_schema::prelude::UNIT
1389 }
1390
1391 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1392 Ok(())
1393 }
1394 }
1395
1396 let mut ser = XmlSerializer::new(Arc::new(XmlCodecSettings::default()));
1397 let result = ser.write_struct(&ATTR_STRUCT, &Empty);
1398 assert!(result.is_err());
1399 }
1400
1401 #[test]
1404 fn namespace_on_struct() {
1405 static NS_SCHEMA: Schema<'static> =
1406 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[])
1407 .with_xml_namespace("https://example.com", None);
1408
1409 struct Empty;
1410 impl SerializableStruct for Empty {
1411 fn schema(&self) -> &Schema<'_> {
1412 &NS_SCHEMA
1413 }
1414
1415 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1416 Ok(())
1417 }
1418 }
1419
1420 let out = serialize(|ser| ser.write_struct(&NS_SCHEMA, &Empty));
1421 assert_eq!(out, "<X xmlns=\"https://example.com\"></X>");
1422 }
1423
1424 #[test]
1425 fn namespace_with_prefix() {
1426 static NS_SCHEMA: Schema<'static> =
1427 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[])
1428 .with_xml_namespace("https://example.com", Some("ex"));
1429
1430 struct Empty;
1431 impl SerializableStruct for Empty {
1432 fn schema(&self) -> &Schema<'_> {
1433 &NS_SCHEMA
1434 }
1435
1436 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1437 Ok(())
1438 }
1439 }
1440
1441 let out = serialize(|ser| ser.write_struct(&NS_SCHEMA, &Empty));
1442 assert_eq!(out, "<X xmlns:ex=\"https://example.com\"></X>");
1443 }
1444
1445 #[test]
1446 fn namespace_with_children() {
1447 static CHILD: Schema<'static> =
1448 Schema::new_member(shape_id!("test", "X$v"), ShapeType::String, "v", 0);
1449 static NS_SCHEMA: Schema<'static> =
1450 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&CHILD])
1451 .with_xml_namespace("urn:foo", None);
1452
1453 struct X;
1454 impl SerializableStruct for X {
1455 fn schema(&self) -> &Schema<'_> {
1456 &NS_SCHEMA
1457 }
1458
1459 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1460 ser.write_string(&CHILD, "hi")
1461 }
1462 }
1463
1464 let out = serialize(|ser| ser.write_struct(&NS_SCHEMA, &X));
1465 assert_eq!(out, "<X xmlns=\"urn:foo\"><v>hi</v></X>");
1466 }
1467
1468 #[test]
1471 fn list_wrapped() {
1472 static LIST_ITEM: Schema<'static> = Schema::new_member(
1475 shape_id!("test", "L$member"),
1476 ShapeType::String,
1477 "member",
1478 0,
1479 );
1480 static LIST_MEMBER: Schema<'static> =
1481 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0);
1482
1483 let out = serialize(|ser| {
1484 ser.write_list(&LIST_MEMBER, &|ser| {
1485 ser.write_string(&LIST_ITEM, "a")?;
1486 ser.write_string(&LIST_ITEM, "b")
1487 })
1488 });
1489 assert_eq!(out, "<items><member>a</member><member>b</member></items>");
1490 }
1491
1492 #[test]
1493 fn list_wrapped_with_xml_name_on_item() {
1494 static LIST_ITEM: Schema<'static> = Schema::new_member(
1496 shape_id!("test", "L$member"),
1497 ShapeType::String,
1498 "member",
1499 0,
1500 )
1501 .with_xml_name("Item");
1502 static LIST_MEMBER: Schema<'static> =
1503 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0);
1504
1505 let out = serialize(|ser| {
1506 ser.write_list(&LIST_MEMBER, &|ser| {
1507 ser.write_string(&LIST_ITEM, "a")?;
1508 ser.write_string(&LIST_ITEM, "b")
1509 })
1510 });
1511 assert_eq!(out, "<items><Item>a</Item><Item>b</Item></items>");
1512 }
1513
1514 #[test]
1515 fn list_flattened() {
1516 static LIST_ITEM: Schema<'static> = Schema::new_member(
1519 shape_id!("test", "L$member"),
1520 ShapeType::String,
1521 "member",
1522 0,
1523 )
1524 .with_xml_name("item");
1525 static LIST_MEMBER: Schema<'static> =
1526 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0)
1527 .with_xml_flattened();
1528
1529 let out = serialize(|ser| {
1530 ser.write_list(&LIST_MEMBER, &|ser| {
1531 ser.write_string(&LIST_ITEM, "a")?;
1532 ser.write_string(&LIST_ITEM, "b")
1533 })
1534 });
1535 assert_eq!(out, "<item>a</item><item>b</item>");
1537 }
1538
1539 #[test]
1542 fn map_wrapped() {
1543 static KEY_SCHEMA: Schema<'static> =
1544 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1545 static VALUE_SCHEMA: Schema<'static> =
1546 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
1547 static MAP_MEMBER: Schema<'static> =
1548 Schema::new_member(shape_id!("test", "S$myMap"), ShapeType::Map, "myMap", 0)
1549 .with_map_members(&KEY_SCHEMA, &VALUE_SCHEMA);
1550
1551 let out = serialize(|ser| {
1552 ser.write_map(&MAP_MEMBER, &|ser| {
1553 ser.write_string(&prelude::STRING, "k1")?;
1554 ser.write_string(&prelude::STRING, "v1")?;
1555 ser.write_string(&prelude::STRING, "k2")?;
1556 ser.write_string(&prelude::STRING, "v2")
1557 })
1558 });
1559 assert_eq!(
1560 out,
1561 "<myMap><entry><key>k1</key><value>v1</value></entry><entry><key>k2</key><value>v2</value></entry></myMap>"
1562 );
1563 }
1564
1565 #[test]
1566 fn map_wrapped_with_renamed_key_value() {
1567 static REN_KEY: Schema<'static> =
1569 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0)
1570 .with_xml_name("Attribute");
1571 static REN_VALUE: Schema<'static> =
1572 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1)
1573 .with_xml_name("Setting");
1574
1575 static MAP_MEMBER: Schema<'static> =
1576 Schema::new_member(shape_id!("test", "S$m"), ShapeType::Map, "m", 0)
1577 .with_map_members(&REN_KEY, &REN_VALUE);
1578
1579 let out = serialize(|ser| {
1580 ser.write_map(&MAP_MEMBER, &|ser| {
1581 ser.write_string(&prelude::STRING, "k")?;
1582 ser.write_string(&prelude::STRING, "v")
1583 })
1584 });
1585 assert_eq!(
1586 out,
1587 "<m><entry><Attribute>k</Attribute><Setting>v</Setting></entry></m>"
1588 );
1589 }
1590
1591 #[test]
1592 fn map_flattened() {
1593 static KEY_SCHEMA: Schema<'static> =
1594 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1595 static VALUE_SCHEMA: Schema<'static> =
1596 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
1597 static MAP_MEMBER: Schema<'static> =
1598 Schema::new_member(shape_id!("test", "S$m"), ShapeType::Map, "m", 0)
1599 .with_xml_flattened()
1600 .with_map_members(&KEY_SCHEMA, &VALUE_SCHEMA);
1601
1602 let out = serialize(|ser| {
1603 ser.write_map(&MAP_MEMBER, &|ser| {
1604 ser.write_string(&prelude::STRING, "a")?;
1605 ser.write_string(&prelude::STRING, "1")?;
1606 ser.write_string(&prelude::STRING, "b")?;
1607 ser.write_string(&prelude::STRING, "2")
1608 })
1609 });
1610 assert_eq!(
1612 out,
1613 "<m><key>a</key><value>1</value></m><m><key>b</key><value>2</value></m>"
1614 );
1615 }
1616
1617 #[test]
1618 fn write_document_returns_error() {
1619 let mut ser = XmlSerializer::new(Arc::new(XmlCodecSettings::default()));
1620 let result = ser.write_document(&SCALAR_MEMBER, &Document::Object(Default::default()));
1621 assert_eq!(
1622 result.unwrap_err().to_string(),
1623 "document types are not supported by REST XML"
1624 );
1625 }
1626
1627 #[test]
1628 fn map_with_struct_value() {
1629 static HI: Schema<'static> =
1630 Schema::new_member(shape_id!("test", "G$hi"), ShapeType::String, "hi", 0);
1631 static GREETING: Schema<'static> = Schema::new_struct(
1632 shape_id!("test", "GreetingStruct"),
1633 ShapeType::Structure,
1634 &[&HI],
1635 );
1636 static KEY: Schema<'static> =
1637 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1638 static VALUE: Schema<'static> =
1639 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
1640 static MAP: Schema<'static> =
1641 Schema::new_member(shape_id!("test", "S$myMap"), ShapeType::Map, "myMap", 0)
1642 .with_map_members(&KEY, &VALUE);
1643
1644 struct G;
1645 impl SerializableStruct for G {
1646 fn schema(&self) -> &Schema<'_> {
1647 &GREETING
1648 }
1649
1650 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1651 ser.write_string(&HI, "bye")
1652 }
1653 }
1654
1655 let out = serialize(|ser| {
1656 ser.write_map(&MAP, &|ser| {
1657 ser.write_string(&prelude::STRING, "baz")?;
1658 ser.write_struct(&GREETING, &G)
1659 })
1660 });
1661 assert_eq!(
1662 out,
1663 "<myMap><entry><key>baz</key><value><hi>bye</hi></value></entry></myMap>"
1664 );
1665 }
1666
1667 #[test]
1687 fn member_schema_struct_emits_attribute_member() {
1688 static ATTR_FIELD_MEMBER: Schema<'static> = Schema::new_member(
1690 shape_id!("test", "Inner$attrField"),
1691 ShapeType::String,
1692 "attrField",
1693 0,
1694 )
1695 .with_xml_name("xsi:someName")
1696 .with_xml_attribute();
1697 static INNER_TARGET: Schema<'static> = Schema::new_struct(
1698 shape_id!("test", "Inner"),
1699 ShapeType::Structure,
1700 &[&ATTR_FIELD_MEMBER],
1701 );
1702 static INNER_MEMBER: Schema<'static> = Schema::new_member(
1706 shape_id!("test", "Outer$nested"),
1707 ShapeType::Structure,
1708 "nested",
1709 0,
1710 );
1711 static OUTER_SCHEMA: Schema<'static> = Schema::new_struct(
1712 shape_id!("test", "Outer"),
1713 ShapeType::Structure,
1714 &[&INNER_MEMBER],
1715 );
1716
1717 struct Inner<'a> {
1718 attr: &'a str,
1719 }
1720 impl SerializableStruct for Inner<'_> {
1721 fn schema(&self) -> &Schema<'_> {
1722 &INNER_TARGET
1723 }
1724
1725 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1726 ser.write_string(&ATTR_FIELD_MEMBER, self.attr)
1727 }
1728 }
1729 struct Outer<'a> {
1730 inner: Inner<'a>,
1731 }
1732 impl SerializableStruct for Outer<'_> {
1733 fn schema(&self) -> &Schema<'_> {
1734 &OUTER_SCHEMA
1735 }
1736
1737 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1738 let _ = &INNER_TARGET;
1742 ser.write_struct(&INNER_MEMBER, &self.inner)
1743 }
1744 }
1745
1746 let outer = Outer {
1747 inner: Inner { attr: "v" },
1748 };
1749 let out = serialize(|ser| ser.write_struct(&OUTER_SCHEMA, &outer));
1750 assert_eq!(out, r#"<Outer><nested xsi:someName="v"></nested></Outer>"#);
1751 }
1752
1753 #[test]
1760 fn map_value_is_inner_map_with_renamed_inner_key_value() {
1761 static INNER_KEY: Schema<'static> = Schema::new_member(
1763 shape_id!("test", "InnerMap$key"),
1764 ShapeType::String,
1765 "key",
1766 0,
1767 )
1768 .with_xml_name("InnerKey");
1769 static INNER_VAL: Schema<'static> = Schema::new_member(
1770 shape_id!("test", "InnerMap$value"),
1771 ShapeType::String,
1772 "value",
1773 1,
1774 )
1775 .with_xml_name("InnerVal");
1776
1777 static OUTER_VALUE: Schema<'static> = Schema::new_member(
1782 shape_id!("test", "OuterMap$value"),
1783 ShapeType::Map,
1784 "value",
1785 1,
1786 )
1787 .with_map_members(&INNER_KEY, &INNER_VAL);
1788
1789 static OUTER_KEY: Schema<'static> = Schema::new_member(
1791 shape_id!("test", "OuterMap$key"),
1792 ShapeType::String,
1793 "key",
1794 0,
1795 );
1796 static OUTER_MAP: Schema<'static> = Schema::new_member(
1797 shape_id!("test", "S$outerMap"),
1798 ShapeType::Map,
1799 "outerMap",
1800 0,
1801 )
1802 .with_map_members(&OUTER_KEY, &OUTER_VALUE);
1803
1804 let out = serialize(|ser| {
1805 ser.write_map(&OUTER_MAP, &|ser| {
1806 ser.write_string(&prelude::STRING, "ok")?;
1807 ser.write_map(&OUTER_VALUE, &|ser| {
1810 ser.write_string(&prelude::STRING, "ik")?;
1811 ser.write_string(&prelude::STRING, "iv")
1812 })
1813 })
1814 });
1815
1816 assert_eq!(
1817 out,
1818 "<outerMap><entry><key>ok</key><value><entry><InnerKey>ik</InnerKey><InnerVal>iv</InnerVal></entry></value></entry></outerMap>"
1819 );
1820 }
1821
1822 #[test]
1826 fn list_member_is_inner_map_with_renamed_inner_key_value() {
1827 static INNER_KEY: Schema<'static> = Schema::new_member(
1828 shape_id!("test", "InnerMap$key"),
1829 ShapeType::String,
1830 "key",
1831 0,
1832 )
1833 .with_xml_name("Attr");
1834 static INNER_VAL: Schema<'static> = Schema::new_member(
1835 shape_id!("test", "InnerMap$value"),
1836 ShapeType::String,
1837 "value",
1838 1,
1839 )
1840 .with_xml_name("Set");
1841
1842 static LIST_ITEM: Schema<'static> = Schema::new_member(
1844 shape_id!("test", "OuterList$member"),
1845 ShapeType::Map,
1846 "member",
1847 0,
1848 )
1849 .with_map_members(&INNER_KEY, &INNER_VAL);
1850
1851 static OUTER_LIST: Schema<'static> =
1852 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0)
1853 .with_list_member(&LIST_ITEM);
1854
1855 let out = serialize(|ser| {
1856 ser.write_list(&OUTER_LIST, &|ser| {
1857 ser.write_map(&LIST_ITEM, &|ser| {
1859 ser.write_string(&prelude::STRING, "k1")?;
1860 ser.write_string(&prelude::STRING, "v1")
1861 })
1862 })
1863 });
1864
1865 assert_eq!(
1869 out,
1870 "<items><member><entry><Attr>k1</Attr><Set>v1</Set></entry></member></items>"
1871 );
1872 }
1873
1874 static CD_ENABLED_X: Schema<'static> = Schema::new_member(
1879 shape_id!("test", "ConnectionDraining$enabled"),
1880 ShapeType::Boolean,
1881 "enabled",
1882 0,
1883 );
1884 static LBA_CD_X: Schema<'static> = Schema::new_member(
1885 shape_id!("test", "LoadBalancerAttributes$connectionDraining"),
1886 ShapeType::Structure,
1887 "connectionDraining",
1888 0,
1889 );
1890 static LBA_SCHEMA_X: Schema<'static> = Schema::new_struct(
1891 shape_id!("test", "LoadBalancerAttributes"),
1892 ShapeType::Structure,
1893 &[&LBA_CD_X],
1894 );
1895
1896 struct ConnectionDrainingX {
1897 enabled: bool,
1898 }
1899 impl SerializableStruct for ConnectionDrainingX {
1900 fn schema(&self) -> &Schema<'_> {
1901 static SCHEMA: Schema<'static> = Schema::new_struct(
1902 aws_smithy_schema::shape_id!("test", "ConnectionDraining"),
1903 aws_smithy_schema::ShapeType::Structure,
1904 &[&CD_ENABLED_X],
1905 );
1906 &SCHEMA
1907 }
1908
1909 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1910 let val = &self.enabled;
1911 ser.write_boolean(&CD_ENABLED_X, *val)
1912 }
1913 }
1914 struct LoadBalancerAttributesX {
1915 connection_draining: ConnectionDrainingX,
1916 }
1917 impl SerializableStruct for LoadBalancerAttributesX {
1918 fn schema(&self) -> &Schema<'_> {
1919 &LBA_SCHEMA_X
1920 }
1921
1922 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1923 ser.write_struct(&LBA_CD_X, &self.connection_draining)
1924 }
1925 }
1926
1927 #[test]
1928 fn required_value_type_false_bool_is_serialized() {
1929 let out = serialize(|ser| {
1930 ser.write_struct(
1931 &LBA_SCHEMA_X,
1932 &LoadBalancerAttributesX {
1933 connection_draining: ConnectionDrainingX { enabled: false },
1934 },
1935 )
1936 });
1937 assert_eq!(
1938 out,
1939 "<LoadBalancerAttributes><connectionDraining><enabled>false</enabled></connectionDraining></LoadBalancerAttributes>",
1940 "the required-default value-type member must be present with false, not dropped"
1941 );
1942 }
1943
1944 #[test]
1949 fn cached_names_do_not_capture_names_from_an_enclosing_list() {
1950 static ROW: Schema<'static> = Schema::new_member(
1951 shape_id!("test", "Rows$member"),
1952 ShapeType::List,
1953 "member",
1954 0,
1955 )
1956 .with_xml_name("Row");
1957 static ROWS: Schema<'static> =
1958 Schema::new_member(shape_id!("test", "S$rows"), ShapeType::List, "rows", 0)
1959 .with_list_member(&ROW);
1960 static COL: Schema<'static> = Schema::new_member(
1961 shape_id!("test", "Cols$member"),
1962 ShapeType::List,
1963 "member",
1964 0,
1965 )
1966 .with_xml_name("Col");
1967 static COLS: Schema<'static> =
1968 Schema::new_member(shape_id!("test", "S$cols"), ShapeType::List, "cols", 1)
1969 .with_list_member(&COL);
1970
1971 let nested = |outer: &'static Schema<'static>| {
1972 serialize(move |ser| {
1973 ser.write_list(outer, &|ser| {
1974 ser.write_list(&prelude::DOCUMENT, &|ser| {
1975 ser.write_string(&prelude::STRING, "a")
1976 })
1977 })
1978 })
1979 };
1980 for _ in 0..2 {
1981 assert_eq!(nested(&ROWS), "<rows><Row><member>a</member></Row></rows>");
1982 assert_eq!(nested(&COLS), "<cols><Col><member>a</member></Col></cols>");
1983 }
1984 }
1985
1986 #[test]
1990 fn flattened_list_item_name_follows_the_enclosing_list() {
1991 static FLAT: Schema<'static> =
1992 Schema::new_member(shape_id!("test", "S$flat"), ShapeType::List, "flat", 0)
1993 .with_xml_flattened();
1994 static OUTER_ITEM: Schema<'static> = Schema::new_member(
1995 shape_id!("test", "Outer$member"),
1996 ShapeType::List,
1997 "member",
1998 0,
1999 )
2000 .with_xml_name("Inherited");
2001 static OUTER: Schema<'static> =
2002 Schema::new_member(shape_id!("test", "S$outer"), ShapeType::List, "outer", 0)
2003 .with_list_member(&OUTER_ITEM);
2004
2005 let flat = || {
2006 serialize(|ser| ser.write_list(&FLAT, &|ser| ser.write_string(&prelude::STRING, "x")))
2007 };
2008 let inherited = || {
2009 serialize(|ser| {
2010 ser.write_list(&OUTER, &|ser| {
2011 ser.write_list(&FLAT, &|ser| ser.write_string(&prelude::STRING, "x"))
2012 })
2013 })
2014 };
2015 for _ in 0..2 {
2016 assert_eq!(flat(), "<flat>x</flat>");
2017 assert_eq!(inherited(), "<outer><Inherited>x</Inherited></outer>");
2018 }
2019 }
2020
2021 #[test]
2024 fn cached_namespaces_are_written_on_every_request() {
2025 static ITEM: Schema<'static> = Schema::new_member(
2026 shape_id!("test", "L$member"),
2027 ShapeType::String,
2028 "member",
2029 0,
2030 )
2031 .with_xml_namespace("urn:item", Some("i"));
2032 static LIST: Schema<'static> =
2033 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0)
2034 .with_list_member(&ITEM);
2035 static KEY: Schema<'static> =
2036 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0)
2037 .with_xml_name("K")
2038 .with_xml_namespace("urn:key", None);
2039 static VALUE: Schema<'static> =
2040 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1)
2041 .with_xml_namespace("urn:value", Some("v"));
2042 static MAP: Schema<'static> =
2043 Schema::new_member(shape_id!("test", "S$m"), ShapeType::Map, "m", 1)
2044 .with_map_members(&KEY, &VALUE);
2045
2046 for _ in 0..2 {
2047 let list = serialize(|ser| {
2048 ser.write_list(&LIST, &|ser| {
2049 ser.write_string(&prelude::STRING, "a")?;
2050 ser.write_integer(&prelude::INTEGER, 1)
2051 })
2052 });
2053 assert_eq!(
2054 list,
2055 "<items><member xmlns:i=\"urn:item\">a</member><member xmlns:i=\"urn:item\">1</member></items>"
2056 );
2057 let map = serialize(|ser| {
2058 ser.write_map(&MAP, &|ser| {
2059 ser.write_string(&prelude::STRING, "k")?;
2060 ser.write_string(&prelude::STRING, "v")
2061 })
2062 });
2063 assert_eq!(
2064 map,
2065 "<m><entry><K xmlns=\"urn:key\">k</K><value xmlns:v=\"urn:value\">v</value></entry></m>"
2066 );
2067 }
2068 }
2069}