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_types::Document;
23use std::sync::Arc;
24
25pub struct XmlSerializer {
27 output: String,
28 settings: Arc<XmlCodecSettings>,
29 frames: Vec<Frame>,
33 map_state: Option<MapState>,
35 list_item_name: Option<String>,
37 list_item_namespace: Option<(String, Option<String>)>,
41 member_filter: MemberFilter,
72 next_root_xml_name: Option<String>,
81 next_root_xml_namespace: Option<(String, Option<String>)>,
91}
92
93#[derive(Debug, Copy, Clone, PartialEq, Eq)]
94enum MemberFilter {
95 None,
97 AttributesOnly,
99 NonAttributesOnly,
101}
102
103#[derive(Debug)]
105struct MapState {
106 entry_name: String,
108 key_name: String,
110 value_name: String,
112 key_namespace: Option<(String, Option<String>)>,
114 value_namespace: Option<(String, Option<String>)>,
116 expecting_key: bool,
118}
119
120#[derive(Debug)]
121enum Frame {
122 StartTagPending { name: String, attrs: String },
127 Open { name: String },
129}
130
131fn write_xmlns_attr(out: &mut String, ns: Option<&(String, Option<String>)>) {
144 use std::fmt::Write;
145 match ns {
146 Some((uri, Some(prefix))) => {
147 write!(out, " xmlns:{prefix}=\"{uri}\"").unwrap();
148 }
149 Some((uri, None)) => {
150 write!(out, " xmlns=\"{uri}\"").unwrap();
151 }
152 None => {}
153 }
154}
155
156impl XmlSerializer {
157 pub(crate) fn new(settings: Arc<XmlCodecSettings>) -> Self {
159 Self {
160 output: String::new(),
161 settings,
162 frames: Vec::new(),
163 map_state: None,
164 list_item_name: None,
165 list_item_namespace: None,
166 member_filter: MemberFilter::None,
167 next_root_xml_name: None,
168 next_root_xml_namespace: None,
169 }
170 }
171
172 pub fn set_next_root_xml_name(&mut self, name: String) {
179 self.next_root_xml_name = Some(name);
180 }
181
182 pub fn set_next_root_xml_namespace(&mut self, uri: String, prefix: Option<String>) {
189 self.next_root_xml_namespace = Some((uri, prefix));
190 }
191
192 fn filter_allows(&self, schema: &Schema<'_>) -> bool {
195 match self.member_filter {
196 MemberFilter::None => true,
197 MemberFilter::AttributesOnly => schema.xml_attribute(),
198 MemberFilter::NonAttributesOnly => !schema.xml_attribute(),
199 }
200 }
201
202 fn element_name<'a>(schema: &'a Schema<'a>) -> &'a str {
212 schema
213 .xml_name()
214 .map(|t| t.value())
215 .or_else(|| schema.original_name())
216 .or_else(|| schema.member_name())
217 .unwrap_or_else(|| schema.shape_id().shape_name())
218 }
219
220 fn flush_start_tag(&mut self) {
225 if let Some(frame) = self.frames.last_mut() {
226 if let Frame::StartTagPending { name, attrs } = frame {
227 self.output.push_str(attrs);
228 self.output.push('>');
229 let name = std::mem::take(name);
230 *frame = Frame::Open { name };
231 }
232 }
233 }
234
235 fn open_element(&mut self, name: &str) {
240 self.output.push('<');
241 self.output.push_str(name);
242 self.frames.push(Frame::StartTagPending {
243 name: name.to_owned(),
244 attrs: String::new(),
245 });
246 }
247
248 fn write_xmlns(&mut self, schema: &Schema<'_>, inherited: Option<&(String, Option<String>)>) {
262 use std::fmt::Write;
263 let is_document_root = self.frames.len() == 1;
264 let root_override =
269 if is_document_root && schema.xml_namespace().is_none() && inherited.is_none() {
270 self.next_root_xml_namespace.take()
271 } else {
272 None
273 };
274 let Some(Frame::StartTagPending { attrs, .. }) = self.frames.last_mut() else {
275 return;
276 };
277 if let Some(ns) = schema.xml_namespace() {
278 match ns.prefix() {
279 Some(prefix) => write!(attrs, " xmlns:{prefix}=\"{}\"", ns.uri()).unwrap(),
280 None => write!(attrs, " xmlns=\"{}\"", ns.uri()).unwrap(),
281 }
282 } else if let Some((uri, prefix)) = inherited {
283 match prefix.as_deref() {
284 Some(p) => write!(attrs, " xmlns:{p}=\"{uri}\"").unwrap(),
285 None => write!(attrs, " xmlns=\"{uri}\"").unwrap(),
286 }
287 } else if let Some((uri, prefix)) = root_override {
288 match prefix {
289 Some(p) => write!(attrs, " xmlns:{p}=\"{uri}\"").unwrap(),
290 None => write!(attrs, " xmlns=\"{uri}\"").unwrap(),
291 }
292 }
293 }
294
295 fn close_element(&mut self) {
304 let frame = self
305 .frames
306 .pop()
307 .expect("close_element called with empty frame stack");
308 match frame {
309 Frame::StartTagPending { name, attrs } => {
310 self.output.push_str(&attrs);
311 self.output.push('>');
312 self.output.push_str("</");
313 self.output.push_str(&name);
314 self.output.push('>');
315 }
316 Frame::Open { name } => {
317 self.output.push_str("</");
318 self.output.push_str(&name);
319 self.output.push('>');
320 }
321 }
322 }
323
324 fn write_safe_element(&mut self, schema: &Schema<'_>, content: &str) {
329 if !self.filter_allows(schema) {
330 return;
331 }
332 if self.try_write_attribute(schema, content) {
333 return;
334 }
335 use std::fmt::Write;
336 self.flush_start_tag();
337 if let Some(map_state) = &mut self.map_state {
338 if map_state.expecting_key {
339 let entry = &map_state.entry_name.clone();
341 let key = &map_state.key_name.clone();
342 write!(self.output, "<{entry}><{key}").unwrap();
343 write_xmlns_attr(&mut self.output, map_state.key_namespace.as_ref());
344 write!(self.output, ">{content}</{key}>").unwrap();
345 map_state.expecting_key = false;
346 } else {
347 let entry = &map_state.entry_name.clone();
349 let value = &map_state.value_name.clone();
350 write!(self.output, "<{value}").unwrap();
351 write_xmlns_attr(&mut self.output, map_state.value_namespace.as_ref());
352 write!(self.output, ">{content}</{value}></{entry}>").unwrap();
353 map_state.expecting_key = true;
354 }
355 } else {
356 let name = if schema.xml_name().is_none() {
357 self.list_item_name
358 .clone()
359 .unwrap_or_else(|| Self::element_name(schema).to_string())
360 } else {
361 Self::element_name(schema).to_string()
362 };
363 self.open_element(&name);
366 let inherited = self.list_item_namespace.clone();
367 self.write_xmlns(schema, inherited.as_ref());
368 self.flush_start_tag();
369 self.output.push_str(content);
370 self.close_element();
371 }
372 }
373
374 fn try_write_attribute(&mut self, schema: &Schema<'_>, value: &str) -> bool {
379 use std::fmt::Write;
380 if !schema.xml_attribute() {
381 return false;
382 }
383 if let Some(Frame::StartTagPending { attrs, .. }) = self.frames.last_mut() {
389 let name = Self::element_name(schema);
390 let escaped = crate::escape::escape(value);
391 write!(attrs, " {name}=\"{escaped}\"").unwrap();
392 return true;
393 }
394 false
395 }
396
397 fn resolve_timestamp_format(&self, schema: &Schema<'_>) -> TimestampFormat {
401 schema
402 .timestamp_format()
403 .map(|t| match t.format() {
404 aws_smithy_schema::traits::TimestampFormat::EpochSeconds => {
405 TimestampFormat::EpochSeconds
406 }
407 aws_smithy_schema::traits::TimestampFormat::DateTime => TimestampFormat::DateTime,
408 aws_smithy_schema::traits::TimestampFormat::HttpDate => TimestampFormat::HttpDate,
409 })
410 .unwrap_or(self.settings.default_timestamp_format())
411 }
412}
413
414impl FinishSerializer for XmlSerializer {
415 fn finish(self) -> Vec<u8> {
416 debug_assert!(
417 self.frames.is_empty(),
418 "XmlSerializer::finish called with {} unclosed frame(s)",
419 self.frames.len()
420 );
421 self.output.into_bytes()
422 }
423}
424
425impl ShapeSerializer for XmlSerializer {
426 fn write_struct(
427 &mut self,
428 schema: &Schema<'_>,
429 value: &dyn SerializableStruct,
430 ) -> Result<(), SerdeError> {
431 if schema.xml_attribute() {
432 return Err(SerdeError::custom(
433 "@xmlAttribute is not supported on aggregate types",
434 ));
435 }
436 if !self.filter_allows(schema) {
437 return Ok(());
438 }
439 self.flush_start_tag();
440
441 let in_map_value = if let Some(map_state) = &mut self.map_state {
443 if map_state.expecting_key {
444 false
445 } else {
446 use std::fmt::Write;
451 let val_name = &map_state.value_name.clone();
452 write!(self.output, "<{val_name}>").unwrap();
453 map_state.expecting_key = true;
454 true
455 }
456 } else {
457 false
458 };
459
460 let saved_map_state = if in_map_value {
462 self.map_state.take()
463 } else {
464 None
465 };
466
467 if in_map_value {
468 let saved_filter = self.member_filter;
479 let has_attrs = schema.member_name().is_some()
485 || schema.members().iter().any(|m| m.xml_attribute());
486 if has_attrs {
487 self.member_filter = MemberFilter::AttributesOnly;
488 value.serialize_members(self)?;
489 }
490 self.member_filter = MemberFilter::NonAttributesOnly;
491 value.serialize_members(self)?;
492 self.member_filter = saved_filter;
493 use std::fmt::Write;
495 let saved = saved_map_state.as_ref().unwrap();
496 let val_name = &saved.value_name;
497 let entry = &saved.entry_name;
498 write!(self.output, "</{val_name}></{entry}>").unwrap();
499 self.map_state = saved_map_state;
500 } else {
501 let root_override = if self.frames.is_empty() {
507 self.next_root_xml_name.take()
508 } else {
509 None
510 };
511 let name = if let Some(override_name) = root_override {
512 override_name
513 } else if schema.xml_name().is_none() {
514 self.list_item_name
515 .clone()
516 .unwrap_or_else(|| Self::element_name(schema).to_string())
517 } else {
518 Self::element_name(schema).to_string()
519 };
520 let saved_list_item = self.list_item_name.take();
521 self.open_element(&name);
522 self.write_xmlns(schema, None);
523 let saved_filter = self.member_filter;
541 let has_attrs = schema.member_name().is_some()
542 || schema.members().iter().any(|m| m.xml_attribute());
543 if has_attrs {
544 self.member_filter = MemberFilter::AttributesOnly;
545 value.serialize_members(self)?;
546 }
547 self.member_filter = MemberFilter::NonAttributesOnly;
548 value.serialize_members(self)?;
549 self.member_filter = saved_filter;
550 self.close_element();
551 self.list_item_name = saved_list_item;
552 }
553 Ok(())
554 }
555
556 fn write_list(
557 &mut self,
558 schema: &Schema<'_>,
559 write_elements: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
560 ) -> Result<(), SerdeError> {
561 if schema.xml_attribute() {
562 return Err(SerdeError::custom(
563 "@xmlAttribute is not supported on aggregate types",
564 ));
565 }
566 if !self.filter_allows(schema) {
567 return Ok(());
568 }
569
570 self.flush_start_tag();
571
572 let in_map_value = if let Some(map_state) = &mut self.map_state {
574 if !map_state.expecting_key {
575 use std::fmt::Write;
576 let val_name = &map_state.value_name.clone();
577 write!(self.output, "<{val_name}>").unwrap();
578 map_state.expecting_key = true;
579 true
580 } else {
581 false
582 }
583 } else {
584 false
585 };
586 let saved_map_state = if in_map_value {
587 self.map_state.take()
588 } else {
589 None
590 };
591
592 let wrapper_name = if schema.xml_name().is_none() {
600 self.list_item_name
601 .clone()
602 .unwrap_or_else(|| Self::element_name(schema).to_string())
603 } else {
604 Self::element_name(schema).to_string()
605 };
606
607 let item_name = if schema.xml_flattened() {
617 if schema.xml_name().is_none() {
619 self.list_item_name
620 .clone()
621 .unwrap_or_else(|| Self::element_name(schema).to_string())
622 } else {
623 Self::element_name(schema).to_string()
624 }
625 } else {
626 schema
627 .member()
628 .and_then(|m| m.xml_name().map(|n| n.value().to_string()))
629 .or_else(|| {
630 schema
631 .member()
632 .and_then(|m| m.member_name().map(|s| s.to_string()))
633 })
634 .unwrap_or_else(|| "member".to_string())
635 };
636
637 let saved_list_item = self.list_item_name.take();
638 self.list_item_name = Some(item_name);
639
640 let saved_list_item_ns = self.list_item_namespace.take();
646 self.list_item_namespace = schema.member().and_then(|m| {
647 m.xml_namespace()
648 .map(|ns| (ns.uri().to_owned(), ns.prefix().map(|p| p.to_owned())))
649 });
650
651 if schema.xml_flattened() || in_map_value {
652 write_elements(self)?;
653 } else {
654 self.open_element(&wrapper_name);
655 self.write_xmlns(schema, None);
658 write_elements(self)?;
659 self.close_element();
660 }
661
662 self.list_item_name = saved_list_item;
663 self.list_item_namespace = saved_list_item_ns;
664
665 if in_map_value {
666 use std::fmt::Write;
667 let saved = saved_map_state.as_ref().unwrap();
668 let val_name = &saved.value_name;
669 let entry = &saved.entry_name;
670 write!(self.output, "</{val_name}></{entry}>").unwrap();
671 self.map_state = saved_map_state;
672 }
673 Ok(())
674 }
675
676 fn write_map(
677 &mut self,
678 schema: &Schema<'_>,
679 write_entries: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
680 ) -> Result<(), SerdeError> {
681 if schema.xml_attribute() {
682 return Err(SerdeError::custom(
683 "@xmlAttribute is not supported on aggregate types",
684 ));
685 }
686 if !self.filter_allows(schema) {
687 return Ok(());
688 }
689
690 self.flush_start_tag();
691
692 let in_map_value = if let Some(map_state) = &mut self.map_state {
694 if !map_state.expecting_key {
695 use std::fmt::Write;
696 let val_name = &map_state.value_name.clone();
697 write!(self.output, "<{val_name}>").unwrap();
698 map_state.expecting_key = true;
699 true
700 } else {
701 false
702 }
703 } else {
704 false
705 };
706
707 let outer_map_state = self.map_state.take();
708
709 let entry_name = if schema.xml_flattened() {
711 Self::element_name(schema).to_string()
712 } else {
713 "entry".to_string()
714 };
715 let key_name = schema
716 .key()
717 .and_then(|k| k.xml_name().map(|n| n.value().to_string()))
718 .unwrap_or_else(|| {
719 schema
720 .key()
721 .and_then(|k| k.member_name().map(|s| s.to_string()))
722 .unwrap_or_else(|| "key".to_string())
723 });
724 let value_name = schema
725 .member()
726 .and_then(|v| v.xml_name().map(|n| n.value().to_string()))
727 .unwrap_or_else(|| {
728 schema
729 .member()
730 .and_then(|v| v.member_name().map(|s| s.to_string()))
731 .unwrap_or_else(|| "value".to_string())
732 });
733
734 self.map_state = Some(MapState {
735 entry_name,
736 key_name,
737 value_name,
738 key_namespace: schema.key().and_then(|k| {
739 k.xml_namespace()
740 .map(|ns| (ns.uri().to_owned(), ns.prefix().map(|p| p.to_owned())))
741 }),
742 value_namespace: schema.member().and_then(|v| {
743 v.xml_namespace()
744 .map(|ns| (ns.uri().to_owned(), ns.prefix().map(|p| p.to_owned())))
745 }),
746 expecting_key: true,
747 });
748
749 let wrapper_name = if schema.xml_name().is_none() {
756 self.list_item_name
757 .clone()
758 .unwrap_or_else(|| Self::element_name(schema).to_string())
759 } else {
760 Self::element_name(schema).to_string()
761 };
762
763 let saved_list_item = self.list_item_name.take();
766
767 if schema.xml_flattened() || in_map_value {
768 write_entries(self)?;
769 } else {
770 self.open_element(&wrapper_name);
771 self.write_xmlns(schema, None);
772 write_entries(self)?;
773 self.close_element();
774 }
775
776 self.list_item_name = saved_list_item;
777
778 self.map_state = outer_map_state;
779
780 if in_map_value {
781 use std::fmt::Write;
782 let saved = self.map_state.as_ref().unwrap();
783 let val_name = &saved.value_name;
784 let entry = &saved.entry_name;
785 write!(self.output, "</{val_name}></{entry}>").unwrap();
786 }
787 Ok(())
788 }
789
790 fn write_boolean(&mut self, schema: &Schema<'_>, value: bool) -> Result<(), SerdeError> {
791 self.write_safe_element(schema, if value { "true" } else { "false" });
792 Ok(())
793 }
794
795 fn write_byte(&mut self, schema: &Schema<'_>, value: i8) -> Result<(), SerdeError> {
796 self.write_safe_element(schema, &value.to_string());
797 Ok(())
798 }
799
800 fn write_short(&mut self, schema: &Schema<'_>, value: i16) -> Result<(), SerdeError> {
801 self.write_safe_element(schema, &value.to_string());
802 Ok(())
803 }
804
805 fn write_integer(&mut self, schema: &Schema<'_>, value: i32) -> Result<(), SerdeError> {
806 self.write_safe_element(schema, &value.to_string());
807 Ok(())
808 }
809
810 fn write_long(&mut self, schema: &Schema<'_>, value: i64) -> Result<(), SerdeError> {
811 self.write_safe_element(schema, &value.to_string());
812 Ok(())
813 }
814
815 fn write_float(&mut self, schema: &Schema<'_>, value: f32) -> Result<(), SerdeError> {
816 let text = if value.is_nan() {
817 "NaN".to_owned()
818 } else if value.is_infinite() {
819 if value.is_sign_positive() {
820 "Infinity".to_owned()
821 } else {
822 "-Infinity".to_owned()
823 }
824 } else {
825 value.to_string()
826 };
827 self.write_safe_element(schema, &text);
828 Ok(())
829 }
830
831 fn write_double(&mut self, schema: &Schema<'_>, value: f64) -> Result<(), SerdeError> {
832 let text = if value.is_nan() {
833 "NaN".to_owned()
834 } else if value.is_infinite() {
835 if value.is_sign_positive() {
836 "Infinity".to_owned()
837 } else {
838 "-Infinity".to_owned()
839 }
840 } else {
841 value.to_string()
842 };
843 self.write_safe_element(schema, &text);
844 Ok(())
845 }
846
847 fn write_big_integer(
848 &mut self,
849 schema: &Schema<'_>,
850 value: &BigInteger,
851 ) -> Result<(), SerdeError> {
852 self.write_safe_element(schema, value.as_ref());
853 Ok(())
854 }
855
856 fn write_big_decimal(
857 &mut self,
858 schema: &Schema<'_>,
859 value: &BigDecimal,
860 ) -> Result<(), SerdeError> {
861 self.write_safe_element(schema, value.as_ref());
862 Ok(())
863 }
864
865 fn write_string(&mut self, schema: &Schema<'_>, value: &str) -> Result<(), SerdeError> {
866 if !self.filter_allows(schema) {
867 return Ok(());
868 }
869 if self.try_write_attribute(schema, value) {
870 return Ok(());
871 }
872 use std::fmt::Write;
873 self.flush_start_tag();
874 let escaped = crate::escape::escape(value);
875 if let Some(map_state) = &mut self.map_state {
876 if map_state.expecting_key {
877 let entry = &map_state.entry_name.clone();
878 let key = &map_state.key_name.clone();
879 write!(self.output, "<{entry}><{key}").unwrap();
880 write_xmlns_attr(&mut self.output, map_state.key_namespace.as_ref());
881 write!(self.output, ">{escaped}</{key}>").unwrap();
882 map_state.expecting_key = false;
883 } else {
884 let entry = &map_state.entry_name.clone();
885 let val_name = &map_state.value_name.clone();
886 write!(self.output, "<{val_name}").unwrap();
887 write_xmlns_attr(&mut self.output, map_state.value_namespace.as_ref());
888 write!(self.output, ">{escaped}</{val_name}></{entry}>").unwrap();
889 map_state.expecting_key = true;
890 }
891 } else {
892 let name = if schema.xml_name().is_none() {
893 self.list_item_name
894 .clone()
895 .unwrap_or_else(|| Self::element_name(schema).to_string())
896 } else {
897 Self::element_name(schema).to_string()
898 };
899 self.open_element(&name);
902 let inherited = self.list_item_namespace.clone();
903 self.write_xmlns(schema, inherited.as_ref());
904 self.flush_start_tag();
905 self.output.push_str(&escaped);
906 self.close_element();
907 }
908 Ok(())
909 }
910
911 fn write_blob(
912 &mut self,
913 schema: &Schema<'_>,
914 value: aws_smithy_types::Blob,
915 ) -> Result<(), SerdeError> {
916 let encoded = aws_smithy_types::base64::encode(value.as_ref());
917 self.write_safe_element(schema, &encoded);
918 Ok(())
919 }
920
921 fn write_timestamp(&mut self, schema: &Schema<'_>, value: &DateTime) -> Result<(), SerdeError> {
922 let format = self.resolve_timestamp_format(schema);
923 let formatted = value
924 .fmt(format)
925 .map_err(|e| SerdeError::custom(e.to_string()))?;
926 self.write_safe_element(schema, &formatted);
928 Ok(())
929 }
930
931 fn write_document(
932 &mut self,
933 _schema: &Schema<'_>,
934 _value: &Document,
935 ) -> Result<(), SerdeError> {
936 Err(SerdeError::custom(
937 "document types are not supported by REST XML",
938 ))
939 }
940
941 fn write_null(&mut self, _schema: &Schema<'_>) -> Result<(), SerdeError> {
942 Ok(())
946 }
947}
948
949#[cfg(test)]
950mod tests {
951 use super::*;
952 use aws_smithy_schema::{prelude, shape_id, Schema, ShapeType};
953 use aws_smithy_types::Blob;
954
955 static NAME_MEMBER: Schema<'static> = Schema::new_member(
957 shape_id!("test", "Person$name"),
958 ShapeType::String,
959 "name",
960 0,
961 );
962 static PERSON_SCHEMA: Schema<'static> = Schema::new_struct(
963 shape_id!("test", "Person"),
964 ShapeType::Structure,
965 &[&NAME_MEMBER],
966 );
967
968 struct Person<'a> {
969 name: &'a str,
970 }
971
972 impl SerializableStruct for Person<'_> {
973 fn serialize_members(
974 &self,
975 serializer: &mut dyn ShapeSerializer,
976 ) -> Result<(), SerdeError> {
977 serializer.write_string(&NAME_MEMBER, self.name)
978 }
979 }
980
981 fn serialize<F>(write: F) -> String
982 where
983 F: FnOnce(&mut XmlSerializer) -> Result<(), SerdeError>,
984 {
985 let mut ser = XmlSerializer::new(Arc::new(XmlCodecSettings::default()));
986 write(&mut ser).expect("serialization failed");
987 String::from_utf8(<XmlSerializer as FinishSerializer>::finish(ser)).unwrap()
988 }
989
990 #[test]
991 fn struct_with_string_member() {
992 let p = Person { name: "Iago" };
993 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &p));
994 assert_eq!(out, "<Person><name>Iago</name></Person>");
995 }
996
997 #[test]
998 fn struct_with_no_members_self_closes() {
999 struct Empty;
1000 impl SerializableStruct for Empty {
1001 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1002 Ok(())
1003 }
1004 }
1005 static EMPTY_SCHEMA: Schema<'static> =
1006 Schema::new_struct(shape_id!("test", "Empty"), ShapeType::Structure, &[]);
1007
1008 let out = serialize(|ser| ser.write_struct(&EMPTY_SCHEMA, &Empty));
1009 assert_eq!(out, "<Empty></Empty>");
1010 }
1011
1012 #[test]
1013 fn struct_string_value_is_escaped() {
1014 let p = Person { name: "<a&b>" };
1015 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &p));
1016 assert_eq!(out, "<Person><name><a&b></name></Person>");
1017 }
1018
1019 #[test]
1020 fn struct_string_value_eol_is_encoded() {
1021 let p = Person { name: "a\r\nb" };
1024 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &p));
1025 assert_eq!(out, "<Person><name>a
b</name></Person>");
1026 }
1027
1028 #[test]
1029 fn nested_structs_close_correctly() {
1030 static INNER_NAME: Schema<'static> = Schema::new_member(
1036 shape_id!("test", "Inner$name"),
1037 ShapeType::String,
1038 "name",
1039 0,
1040 );
1041 static OUTER_INNER: Schema<'static> = Schema::new_member(
1042 shape_id!("test", "Outer$inner"),
1043 ShapeType::Structure,
1044 "inner",
1045 0,
1046 );
1047 static OUTER_SCHEMA: Schema<'static> = Schema::new_struct(
1048 shape_id!("test", "Outer"),
1049 ShapeType::Structure,
1050 &[&OUTER_INNER],
1051 );
1052
1053 struct Inner<'a> {
1054 name: &'a str,
1055 }
1056 impl SerializableStruct for Inner<'_> {
1057 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1058 ser.write_string(&INNER_NAME, self.name)
1059 }
1060 }
1061 struct Outer<'a> {
1062 inner: Inner<'a>,
1063 }
1064 impl SerializableStruct for Outer<'_> {
1065 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1066 ser.write_struct(&OUTER_INNER, &self.inner)
1070 }
1071 }
1072
1073 let o = Outer {
1074 inner: Inner { name: "v" },
1075 };
1076 let out = serialize(|ser| ser.write_struct(&OUTER_SCHEMA, &o));
1077 assert_eq!(out, "<Outer><inner><name>v</name></inner></Outer>");
1078 }
1079
1080 #[test]
1081 fn xml_name_overrides_member_name() {
1082 static RENAMED_MEMBER: Schema<'static> = Schema::new_member(
1083 shape_id!("test", "Person$name"),
1084 ShapeType::String,
1085 "name",
1086 0,
1087 )
1088 .with_xml_name("FullName");
1089 static PERSON_SCHEMA: Schema<'static> = Schema::new_struct(
1090 shape_id!("test", "Person"),
1091 ShapeType::Structure,
1092 &[&RENAMED_MEMBER],
1093 );
1094
1095 struct P;
1096 impl SerializableStruct for P {
1097 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1098 ser.write_string(&RENAMED_MEMBER, "v")
1099 }
1100 }
1101
1102 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &P));
1103 assert_eq!(out, "<Person><FullName>v</FullName></Person>");
1104 }
1105
1106 #[test]
1111 fn xml_name_and_namespace_from_a_runtime_schema() {
1112 let arena: Vec<String> = vec![
1114 String::from("name"), String::from("RuntimeFullName"), String::from("https://ns.example/"), ];
1118
1119 let member: Schema<'_> = Schema::new_member(
1120 shape_id!("test", "Person$name"),
1121 ShapeType::String,
1122 &arena[0],
1123 0,
1124 )
1125 .with_xml_name(&arena[1]);
1126
1127 let members = [&member];
1128 let person: Schema<'_> =
1129 Schema::new_struct(shape_id!("test", "Person"), ShapeType::Structure, &members)
1130 .with_xml_namespace(&arena[2], None);
1131
1132 struct P<'a>(&'a Schema<'a>);
1133 impl SerializableStruct for P<'_> {
1134 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1135 ser.write_string(self.0, "v")
1136 }
1137 }
1138
1139 let out = serialize(|ser| ser.write_struct(&person, &P(&member)));
1140 assert_eq!(
1141 out,
1142 "<Person xmlns=\"https://ns.example/\"><RuntimeFullName>v</RuntimeFullName></Person>"
1143 );
1144 }
1145
1146 #[test]
1147 fn original_name_overrides_id_for_synthetic_root() {
1148 static SYNTHETIC: Schema<'static> = Schema::new_struct(
1152 shape_id!("test.synthetic", "FooInput"),
1153 ShapeType::Structure,
1154 &[],
1155 )
1156 .with_original_name("FooRequest");
1157
1158 struct Empty;
1159 impl SerializableStruct for Empty {
1160 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1161 Ok(())
1162 }
1163 }
1164
1165 let out = serialize(|ser| ser.write_struct(&SYNTHETIC, &Empty));
1166 assert_eq!(out, "<FooRequest></FooRequest>");
1167 }
1168
1169 static SCALAR_MEMBER: Schema<'static> =
1172 Schema::new_member(shape_id!("test", "S$v"), ShapeType::Integer, "v", 0);
1173
1174 #[test]
1175 fn write_boolean_true() {
1176 let out = serialize(|ser| ser.write_boolean(&SCALAR_MEMBER, true));
1177 assert_eq!(out, "<v>true</v>");
1178 }
1179
1180 #[test]
1181 fn write_boolean_false() {
1182 let out = serialize(|ser| ser.write_boolean(&SCALAR_MEMBER, false));
1183 assert_eq!(out, "<v>false</v>");
1184 }
1185
1186 #[test]
1187 fn write_integer_negative() {
1188 let out = serialize(|ser| ser.write_integer(&SCALAR_MEMBER, -42));
1189 assert_eq!(out, "<v>-42</v>");
1190 }
1191
1192 #[test]
1193 fn write_long_large() {
1194 let out = serialize(|ser| ser.write_long(&SCALAR_MEMBER, i64::MAX));
1195 assert_eq!(out, format!("<v>{}</v>", i64::MAX));
1196 }
1197
1198 #[test]
1199 fn write_float_special_values() {
1200 let out = serialize(|ser| ser.write_float(&SCALAR_MEMBER, f32::NAN));
1201 assert_eq!(out, "<v>NaN</v>");
1202 let out = serialize(|ser| ser.write_float(&SCALAR_MEMBER, f32::INFINITY));
1203 assert_eq!(out, "<v>Infinity</v>");
1204 let out = serialize(|ser| ser.write_float(&SCALAR_MEMBER, f32::NEG_INFINITY));
1205 assert_eq!(out, "<v>-Infinity</v>");
1206 }
1207
1208 #[test]
1209 fn write_double_normal() {
1210 let out = serialize(|ser| ser.write_double(&SCALAR_MEMBER, 1.5));
1211 assert_eq!(out, "<v>1.5</v>");
1212 }
1213
1214 #[test]
1215 fn write_blob_base64() {
1216 let blob = Blob::new(b"hello");
1217 let out = serialize(|ser| ser.write_blob(&SCALAR_MEMBER, blob.clone()));
1218 assert_eq!(out, "<v>aGVsbG8=</v>");
1219 }
1220
1221 #[test]
1222 fn write_timestamp_default_datetime() {
1223 let ts = DateTime::from_secs(1515531081);
1225 let out = serialize(|ser| ser.write_timestamp(&SCALAR_MEMBER, &ts));
1226 assert_eq!(out, "<v>2018-01-09T20:51:21Z</v>");
1227 }
1228
1229 #[test]
1230 fn write_timestamp_epoch_seconds_override() {
1231 use aws_smithy_schema::traits::TimestampFormat as SchemaTimestampFormat;
1232 static TS_MEMBER: Schema<'static> =
1233 Schema::new_member(shape_id!("test", "S$t"), ShapeType::Timestamp, "t", 0)
1234 .with_timestamp_format(SchemaTimestampFormat::EpochSeconds);
1235 let ts = DateTime::from_secs(1515531081);
1236 let out = serialize(|ser| ser.write_timestamp(&TS_MEMBER, &ts));
1237 assert_eq!(out, "<t>1515531081</t>");
1238 }
1239
1240 #[test]
1241 fn write_null_emits_nothing() {
1242 let out = serialize(|ser| ser.write_null(&SCALAR_MEMBER));
1243 assert_eq!(out, "");
1244 }
1245
1246 #[test]
1249 fn attribute_string_on_struct() {
1250 static ATTR_MEMBER: Schema<'static> =
1251 Schema::new_member(shape_id!("test", "X$id"), ShapeType::String, "id", 0)
1252 .with_xml_attribute();
1253 static CHILD_MEMBER: Schema<'static> =
1254 Schema::new_member(shape_id!("test", "X$name"), ShapeType::String, "name", 1);
1255 static X_SCHEMA: Schema<'static> = Schema::new_struct(
1256 shape_id!("test", "X"),
1257 ShapeType::Structure,
1258 &[&ATTR_MEMBER, &CHILD_MEMBER],
1259 );
1260
1261 struct X;
1262 impl SerializableStruct for X {
1263 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1264 ser.write_string(&ATTR_MEMBER, "42")?;
1265 ser.write_string(&CHILD_MEMBER, "hello")
1266 }
1267 }
1268
1269 let out = serialize(|ser| ser.write_struct(&X_SCHEMA, &X));
1270 assert_eq!(out, "<X id=\"42\"><name>hello</name></X>");
1271 }
1272
1273 #[test]
1274 fn attribute_integer_on_struct() {
1275 static ATTR: Schema<'static> =
1276 Schema::new_member(shape_id!("test", "X$count"), ShapeType::Integer, "count", 0)
1277 .with_xml_attribute();
1278 static X_SCHEMA: Schema<'static> =
1279 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&ATTR]);
1280
1281 struct X;
1282 impl SerializableStruct for X {
1283 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1284 ser.write_integer(&ATTR, 7)
1285 }
1286 }
1287
1288 let out = serialize(|ser| ser.write_struct(&X_SCHEMA, &X));
1289 assert_eq!(out, "<X count=\"7\"></X>");
1290 }
1291
1292 #[test]
1293 fn attribute_value_is_escaped() {
1294 static ATTR: Schema<'static> =
1295 Schema::new_member(shape_id!("test", "X$v"), ShapeType::String, "v", 0)
1296 .with_xml_attribute();
1297 static X_SCHEMA: Schema<'static> =
1298 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&ATTR]);
1299
1300 struct X;
1301 impl SerializableStruct for X {
1302 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1303 ser.write_string(&ATTR, "a\"b&c")
1304 }
1305 }
1306
1307 let out = serialize(|ser| ser.write_struct(&X_SCHEMA, &X));
1308 assert_eq!(out, "<X v=\"a"b&c\"></X>");
1309 }
1310
1311 #[test]
1312 fn attribute_on_struct_returns_error() {
1313 static ATTR_STRUCT: Schema<'static> = Schema::new_member(
1314 shape_id!("test", "X$inner"),
1315 ShapeType::Structure,
1316 "inner",
1317 0,
1318 )
1319 .with_xml_attribute();
1320
1321 struct Empty;
1322 impl SerializableStruct for Empty {
1323 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1324 Ok(())
1325 }
1326 }
1327
1328 let mut ser = XmlSerializer::new(Arc::new(XmlCodecSettings::default()));
1329 let result = ser.write_struct(&ATTR_STRUCT, &Empty);
1330 assert!(result.is_err());
1331 }
1332
1333 #[test]
1336 fn namespace_on_struct() {
1337 static NS_SCHEMA: Schema<'static> =
1338 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[])
1339 .with_xml_namespace("https://example.com", None);
1340
1341 struct Empty;
1342 impl SerializableStruct for Empty {
1343 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1344 Ok(())
1345 }
1346 }
1347
1348 let out = serialize(|ser| ser.write_struct(&NS_SCHEMA, &Empty));
1349 assert_eq!(out, "<X xmlns=\"https://example.com\"></X>");
1350 }
1351
1352 #[test]
1353 fn namespace_with_prefix() {
1354 static NS_SCHEMA: Schema<'static> =
1355 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[])
1356 .with_xml_namespace("https://example.com", Some("ex"));
1357
1358 struct Empty;
1359 impl SerializableStruct for Empty {
1360 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1361 Ok(())
1362 }
1363 }
1364
1365 let out = serialize(|ser| ser.write_struct(&NS_SCHEMA, &Empty));
1366 assert_eq!(out, "<X xmlns:ex=\"https://example.com\"></X>");
1367 }
1368
1369 #[test]
1370 fn namespace_with_children() {
1371 static CHILD: Schema<'static> =
1372 Schema::new_member(shape_id!("test", "X$v"), ShapeType::String, "v", 0);
1373 static NS_SCHEMA: Schema<'static> =
1374 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&CHILD])
1375 .with_xml_namespace("urn:foo", None);
1376
1377 struct X;
1378 impl SerializableStruct for X {
1379 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1380 ser.write_string(&CHILD, "hi")
1381 }
1382 }
1383
1384 let out = serialize(|ser| ser.write_struct(&NS_SCHEMA, &X));
1385 assert_eq!(out, "<X xmlns=\"urn:foo\"><v>hi</v></X>");
1386 }
1387
1388 #[test]
1391 fn list_wrapped() {
1392 static LIST_ITEM: Schema<'static> = Schema::new_member(
1395 shape_id!("test", "L$member"),
1396 ShapeType::String,
1397 "member",
1398 0,
1399 );
1400 static LIST_MEMBER: Schema<'static> =
1401 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0);
1402
1403 let out = serialize(|ser| {
1404 ser.write_list(&LIST_MEMBER, &|ser| {
1405 ser.write_string(&LIST_ITEM, "a")?;
1406 ser.write_string(&LIST_ITEM, "b")
1407 })
1408 });
1409 assert_eq!(out, "<items><member>a</member><member>b</member></items>");
1410 }
1411
1412 #[test]
1413 fn list_wrapped_with_xml_name_on_item() {
1414 static LIST_ITEM: Schema<'static> = Schema::new_member(
1416 shape_id!("test", "L$member"),
1417 ShapeType::String,
1418 "member",
1419 0,
1420 )
1421 .with_xml_name("Item");
1422 static LIST_MEMBER: Schema<'static> =
1423 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0);
1424
1425 let out = serialize(|ser| {
1426 ser.write_list(&LIST_MEMBER, &|ser| {
1427 ser.write_string(&LIST_ITEM, "a")?;
1428 ser.write_string(&LIST_ITEM, "b")
1429 })
1430 });
1431 assert_eq!(out, "<items><Item>a</Item><Item>b</Item></items>");
1432 }
1433
1434 #[test]
1435 fn list_flattened() {
1436 static LIST_ITEM: Schema<'static> = Schema::new_member(
1439 shape_id!("test", "L$member"),
1440 ShapeType::String,
1441 "member",
1442 0,
1443 )
1444 .with_xml_name("item");
1445 static LIST_MEMBER: Schema<'static> =
1446 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0)
1447 .with_xml_flattened();
1448
1449 let out = serialize(|ser| {
1450 ser.write_list(&LIST_MEMBER, &|ser| {
1451 ser.write_string(&LIST_ITEM, "a")?;
1452 ser.write_string(&LIST_ITEM, "b")
1453 })
1454 });
1455 assert_eq!(out, "<item>a</item><item>b</item>");
1457 }
1458
1459 #[test]
1462 fn map_wrapped() {
1463 static KEY_SCHEMA: Schema<'static> =
1464 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1465 static VALUE_SCHEMA: Schema<'static> =
1466 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
1467 static MAP_MEMBER: Schema<'static> =
1468 Schema::new_member(shape_id!("test", "S$myMap"), ShapeType::Map, "myMap", 0)
1469 .with_map_members(&KEY_SCHEMA, &VALUE_SCHEMA);
1470
1471 let out = serialize(|ser| {
1472 ser.write_map(&MAP_MEMBER, &|ser| {
1473 ser.write_string(&prelude::STRING, "k1")?;
1474 ser.write_string(&prelude::STRING, "v1")?;
1475 ser.write_string(&prelude::STRING, "k2")?;
1476 ser.write_string(&prelude::STRING, "v2")
1477 })
1478 });
1479 assert_eq!(
1480 out,
1481 "<myMap><entry><key>k1</key><value>v1</value></entry><entry><key>k2</key><value>v2</value></entry></myMap>"
1482 );
1483 }
1484
1485 #[test]
1486 fn map_wrapped_with_renamed_key_value() {
1487 static REN_KEY: Schema<'static> =
1489 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0)
1490 .with_xml_name("Attribute");
1491 static REN_VALUE: Schema<'static> =
1492 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1)
1493 .with_xml_name("Setting");
1494
1495 static MAP_MEMBER: Schema<'static> =
1496 Schema::new_member(shape_id!("test", "S$m"), ShapeType::Map, "m", 0)
1497 .with_map_members(&REN_KEY, &REN_VALUE);
1498
1499 let out = serialize(|ser| {
1500 ser.write_map(&MAP_MEMBER, &|ser| {
1501 ser.write_string(&prelude::STRING, "k")?;
1502 ser.write_string(&prelude::STRING, "v")
1503 })
1504 });
1505 assert_eq!(
1506 out,
1507 "<m><entry><Attribute>k</Attribute><Setting>v</Setting></entry></m>"
1508 );
1509 }
1510
1511 #[test]
1512 fn map_flattened() {
1513 static KEY_SCHEMA: Schema<'static> =
1514 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1515 static VALUE_SCHEMA: Schema<'static> =
1516 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
1517 static MAP_MEMBER: Schema<'static> =
1518 Schema::new_member(shape_id!("test", "S$m"), ShapeType::Map, "m", 0)
1519 .with_xml_flattened()
1520 .with_map_members(&KEY_SCHEMA, &VALUE_SCHEMA);
1521
1522 let out = serialize(|ser| {
1523 ser.write_map(&MAP_MEMBER, &|ser| {
1524 ser.write_string(&prelude::STRING, "a")?;
1525 ser.write_string(&prelude::STRING, "1")?;
1526 ser.write_string(&prelude::STRING, "b")?;
1527 ser.write_string(&prelude::STRING, "2")
1528 })
1529 });
1530 assert_eq!(
1532 out,
1533 "<m><key>a</key><value>1</value></m><m><key>b</key><value>2</value></m>"
1534 );
1535 }
1536
1537 #[test]
1538 fn write_document_returns_error() {
1539 let mut ser = XmlSerializer::new(Arc::new(XmlCodecSettings::default()));
1540 let result = ser.write_document(&SCALAR_MEMBER, &Document::Object(Default::default()));
1541 assert_eq!(
1542 result.unwrap_err().to_string(),
1543 "document types are not supported by REST XML"
1544 );
1545 }
1546
1547 #[test]
1548 fn map_with_struct_value() {
1549 static HI: Schema<'static> =
1550 Schema::new_member(shape_id!("test", "G$hi"), ShapeType::String, "hi", 0);
1551 static GREETING: Schema<'static> = Schema::new_struct(
1552 shape_id!("test", "GreetingStruct"),
1553 ShapeType::Structure,
1554 &[&HI],
1555 );
1556 static KEY: Schema<'static> =
1557 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1558 static VALUE: Schema<'static> =
1559 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
1560 static MAP: Schema<'static> =
1561 Schema::new_member(shape_id!("test", "S$myMap"), ShapeType::Map, "myMap", 0)
1562 .with_map_members(&KEY, &VALUE);
1563
1564 struct G;
1565 impl SerializableStruct for G {
1566 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1567 ser.write_string(&HI, "bye")
1568 }
1569 }
1570
1571 let out = serialize(|ser| {
1572 ser.write_map(&MAP, &|ser| {
1573 ser.write_string(&prelude::STRING, "baz")?;
1574 ser.write_struct(&GREETING, &G)
1575 })
1576 });
1577 assert_eq!(
1578 out,
1579 "<myMap><entry><key>baz</key><value><hi>bye</hi></value></entry></myMap>"
1580 );
1581 }
1582
1583 #[test]
1603 fn member_schema_struct_emits_attribute_member() {
1604 static ATTR_FIELD_MEMBER: Schema<'static> = Schema::new_member(
1606 shape_id!("test", "Inner$attrField"),
1607 ShapeType::String,
1608 "attrField",
1609 0,
1610 )
1611 .with_xml_name("xsi:someName")
1612 .with_xml_attribute();
1613 static INNER_TARGET: Schema<'static> = Schema::new_struct(
1614 shape_id!("test", "Inner"),
1615 ShapeType::Structure,
1616 &[&ATTR_FIELD_MEMBER],
1617 );
1618 static INNER_MEMBER: Schema<'static> = Schema::new_member(
1622 shape_id!("test", "Outer$nested"),
1623 ShapeType::Structure,
1624 "nested",
1625 0,
1626 );
1627 static OUTER_SCHEMA: Schema<'static> = Schema::new_struct(
1628 shape_id!("test", "Outer"),
1629 ShapeType::Structure,
1630 &[&INNER_MEMBER],
1631 );
1632
1633 struct Inner<'a> {
1634 attr: &'a str,
1635 }
1636 impl SerializableStruct for Inner<'_> {
1637 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1638 ser.write_string(&ATTR_FIELD_MEMBER, self.attr)
1639 }
1640 }
1641 struct Outer<'a> {
1642 inner: Inner<'a>,
1643 }
1644 impl SerializableStruct for Outer<'_> {
1645 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1646 let _ = &INNER_TARGET;
1650 ser.write_struct(&INNER_MEMBER, &self.inner)
1651 }
1652 }
1653
1654 let outer = Outer {
1655 inner: Inner { attr: "v" },
1656 };
1657 let out = serialize(|ser| ser.write_struct(&OUTER_SCHEMA, &outer));
1658 assert_eq!(out, r#"<Outer><nested xsi:someName="v"></nested></Outer>"#);
1659 }
1660
1661 #[test]
1668 fn map_value_is_inner_map_with_renamed_inner_key_value() {
1669 static INNER_KEY: Schema<'static> = Schema::new_member(
1671 shape_id!("test", "InnerMap$key"),
1672 ShapeType::String,
1673 "key",
1674 0,
1675 )
1676 .with_xml_name("InnerKey");
1677 static INNER_VAL: Schema<'static> = Schema::new_member(
1678 shape_id!("test", "InnerMap$value"),
1679 ShapeType::String,
1680 "value",
1681 1,
1682 )
1683 .with_xml_name("InnerVal");
1684
1685 static OUTER_VALUE: Schema<'static> = Schema::new_member(
1690 shape_id!("test", "OuterMap$value"),
1691 ShapeType::Map,
1692 "value",
1693 1,
1694 )
1695 .with_map_members(&INNER_KEY, &INNER_VAL);
1696
1697 static OUTER_KEY: Schema<'static> = Schema::new_member(
1699 shape_id!("test", "OuterMap$key"),
1700 ShapeType::String,
1701 "key",
1702 0,
1703 );
1704 static OUTER_MAP: Schema<'static> = Schema::new_member(
1705 shape_id!("test", "S$outerMap"),
1706 ShapeType::Map,
1707 "outerMap",
1708 0,
1709 )
1710 .with_map_members(&OUTER_KEY, &OUTER_VALUE);
1711
1712 let out = serialize(|ser| {
1713 ser.write_map(&OUTER_MAP, &|ser| {
1714 ser.write_string(&prelude::STRING, "ok")?;
1715 ser.write_map(&OUTER_VALUE, &|ser| {
1718 ser.write_string(&prelude::STRING, "ik")?;
1719 ser.write_string(&prelude::STRING, "iv")
1720 })
1721 })
1722 });
1723
1724 assert_eq!(
1725 out,
1726 "<outerMap><entry><key>ok</key><value><entry><InnerKey>ik</InnerKey><InnerVal>iv</InnerVal></entry></value></entry></outerMap>"
1727 );
1728 }
1729
1730 #[test]
1734 fn list_member_is_inner_map_with_renamed_inner_key_value() {
1735 static INNER_KEY: Schema<'static> = Schema::new_member(
1736 shape_id!("test", "InnerMap$key"),
1737 ShapeType::String,
1738 "key",
1739 0,
1740 )
1741 .with_xml_name("Attr");
1742 static INNER_VAL: Schema<'static> = Schema::new_member(
1743 shape_id!("test", "InnerMap$value"),
1744 ShapeType::String,
1745 "value",
1746 1,
1747 )
1748 .with_xml_name("Set");
1749
1750 static LIST_ITEM: Schema<'static> = Schema::new_member(
1752 shape_id!("test", "OuterList$member"),
1753 ShapeType::Map,
1754 "member",
1755 0,
1756 )
1757 .with_map_members(&INNER_KEY, &INNER_VAL);
1758
1759 static OUTER_LIST: Schema<'static> =
1760 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0)
1761 .with_list_member(&LIST_ITEM);
1762
1763 let out = serialize(|ser| {
1764 ser.write_list(&OUTER_LIST, &|ser| {
1765 ser.write_map(&LIST_ITEM, &|ser| {
1767 ser.write_string(&prelude::STRING, "k1")?;
1768 ser.write_string(&prelude::STRING, "v1")
1769 })
1770 })
1771 });
1772
1773 assert_eq!(
1777 out,
1778 "<items><member><entry><Attr>k1</Attr><Set>v1</Set></entry></member></items>"
1779 );
1780 }
1781
1782 static CD_ENABLED_X: Schema<'static> = Schema::new_member(
1787 shape_id!("test", "ConnectionDraining$enabled"),
1788 ShapeType::Boolean,
1789 "enabled",
1790 0,
1791 );
1792 static LBA_CD_X: Schema<'static> = Schema::new_member(
1793 shape_id!("test", "LoadBalancerAttributes$connectionDraining"),
1794 ShapeType::Structure,
1795 "connectionDraining",
1796 0,
1797 );
1798 static LBA_SCHEMA_X: Schema<'static> = Schema::new_struct(
1799 shape_id!("test", "LoadBalancerAttributes"),
1800 ShapeType::Structure,
1801 &[&LBA_CD_X],
1802 );
1803
1804 struct ConnectionDrainingX {
1805 enabled: bool,
1806 }
1807 impl SerializableStruct for ConnectionDrainingX {
1808 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1809 let val = &self.enabled;
1810 ser.write_boolean(&CD_ENABLED_X, *val)
1811 }
1812 }
1813 struct LoadBalancerAttributesX {
1814 connection_draining: ConnectionDrainingX,
1815 }
1816 impl SerializableStruct for LoadBalancerAttributesX {
1817 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1818 ser.write_struct(&LBA_CD_X, &self.connection_draining)
1819 }
1820 }
1821
1822 #[test]
1823 fn required_value_type_false_bool_is_serialized() {
1824 let out = serialize(|ser| {
1825 ser.write_struct(
1826 &LBA_SCHEMA_X,
1827 &LoadBalancerAttributesX {
1828 connection_draining: ConnectionDrainingX { enabled: false },
1829 },
1830 )
1831 });
1832 assert_eq!(
1833 out,
1834 "<LoadBalancerAttributes><connectionDraining><enabled>false</enabled></connectionDraining></LoadBalancerAttributes>",
1835 "the required-default value-type member must be present with false, not dropped"
1836 );
1837 }
1838}