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, Document};
21use std::sync::Arc;
22
23pub struct XmlSerializer {
25 output: String,
26 settings: Arc<XmlCodecSettings>,
27 frames: Vec<Frame>,
31 map_state: Option<MapState>,
33 list_item_name: Option<String>,
35 list_item_namespace: Option<(String, Option<String>)>,
39 member_filter: MemberFilter,
70 next_root_xml_name: Option<String>,
79 next_root_xml_namespace: Option<(String, Option<String>)>,
89}
90
91#[derive(Debug, Copy, Clone, PartialEq, Eq)]
92enum MemberFilter {
93 None,
95 AttributesOnly,
97 NonAttributesOnly,
99}
100
101#[derive(Debug)]
103struct MapState {
104 entry_name: String,
106 key_name: String,
108 value_name: String,
110 key_namespace: Option<(String, Option<String>)>,
112 value_namespace: Option<(String, Option<String>)>,
114 value_schema: Option<&'static Schema>,
119 expecting_key: bool,
121}
122
123#[derive(Debug)]
124enum Frame {
125 StartTagPending { name: String, attrs: String },
130 Open { name: String },
132}
133
134fn write_xmlns_attr(out: &mut String, ns: Option<&(String, Option<String>)>) {
147 use std::fmt::Write;
148 match ns {
149 Some((uri, Some(prefix))) => {
150 write!(out, " xmlns:{prefix}=\"{uri}\"").unwrap();
151 }
152 Some((uri, None)) => {
153 write!(out, " xmlns=\"{uri}\"").unwrap();
154 }
155 None => {}
156 }
157}
158
159impl XmlSerializer {
160 pub(crate) fn new(settings: Arc<XmlCodecSettings>) -> Self {
162 Self {
163 output: String::new(),
164 settings,
165 frames: Vec::new(),
166 map_state: None,
167 list_item_name: None,
168 list_item_namespace: None,
169 member_filter: MemberFilter::None,
170 next_root_xml_name: None,
171 next_root_xml_namespace: None,
172 }
173 }
174
175 pub fn set_next_root_xml_name(&mut self, name: String) {
182 self.next_root_xml_name = Some(name);
183 }
184
185 pub fn set_next_root_xml_namespace(&mut self, uri: String, prefix: Option<String>) {
192 self.next_root_xml_namespace = Some((uri, prefix));
193 }
194
195 fn filter_allows(&self, schema: &Schema) -> bool {
198 match self.member_filter {
199 MemberFilter::None => true,
200 MemberFilter::AttributesOnly => schema.xml_attribute(),
201 MemberFilter::NonAttributesOnly => !schema.xml_attribute(),
202 }
203 }
204
205 fn element_name(schema: &Schema) -> &str {
215 schema
216 .xml_name()
217 .map(|t| t.value())
218 .or_else(|| schema.original_name())
219 .or_else(|| schema.member_name())
220 .unwrap_or_else(|| schema.shape_id().shape_name())
221 }
222
223 fn flush_start_tag(&mut self) {
228 if let Some(frame) = self.frames.last_mut() {
229 if let Frame::StartTagPending { name, attrs } = frame {
230 self.output.push_str(attrs);
231 self.output.push('>');
232 let name = std::mem::take(name);
233 *frame = Frame::Open { name };
234 }
235 }
236 }
237
238 fn open_element(&mut self, name: &str) {
243 self.output.push('<');
244 self.output.push_str(name);
245 self.frames.push(Frame::StartTagPending {
246 name: name.to_owned(),
247 attrs: String::new(),
248 });
249 }
250
251 fn write_xmlns(&mut self, schema: &Schema, inherited: Option<&(String, Option<String>)>) {
265 use std::fmt::Write;
266 let is_document_root = self.frames.len() == 1;
267 let root_override =
272 if is_document_root && schema.xml_namespace().is_none() && inherited.is_none() {
273 self.next_root_xml_namespace.take()
274 } else {
275 None
276 };
277 let Some(Frame::StartTagPending { attrs, .. }) = self.frames.last_mut() else {
278 return;
279 };
280 if let Some(ns) = schema.xml_namespace() {
281 match ns.prefix() {
282 Some(prefix) => write!(attrs, " xmlns:{prefix}=\"{}\"", ns.uri()).unwrap(),
283 None => write!(attrs, " xmlns=\"{}\"", ns.uri()).unwrap(),
284 }
285 } else if let Some((uri, prefix)) = inherited {
286 match prefix.as_deref() {
287 Some(p) => write!(attrs, " xmlns:{p}=\"{uri}\"").unwrap(),
288 None => write!(attrs, " xmlns=\"{uri}\"").unwrap(),
289 }
290 } else if let Some((uri, prefix)) = root_override {
291 match prefix {
292 Some(p) => write!(attrs, " xmlns:{p}=\"{uri}\"").unwrap(),
293 None => write!(attrs, " xmlns=\"{uri}\"").unwrap(),
294 }
295 }
296 }
297
298 fn close_element(&mut self) {
307 let frame = self
308 .frames
309 .pop()
310 .expect("close_element called with empty frame stack");
311 match frame {
312 Frame::StartTagPending { name, attrs } => {
313 self.output.push_str(&attrs);
314 self.output.push('>');
315 self.output.push_str("</");
316 self.output.push_str(&name);
317 self.output.push('>');
318 }
319 Frame::Open { name } => {
320 self.output.push_str("</");
321 self.output.push_str(&name);
322 self.output.push('>');
323 }
324 }
325 }
326
327 fn write_safe_element(&mut self, schema: &Schema, content: &str) {
332 if !self.filter_allows(schema) {
333 return;
334 }
335 if self.try_write_attribute(schema, content) {
336 return;
337 }
338 use std::fmt::Write;
339 self.flush_start_tag();
340 if let Some(map_state) = &mut self.map_state {
341 if map_state.expecting_key {
342 let entry = &map_state.entry_name.clone();
344 let key = &map_state.key_name.clone();
345 write!(self.output, "<{entry}><{key}").unwrap();
346 write_xmlns_attr(&mut self.output, map_state.key_namespace.as_ref());
347 write!(self.output, ">{content}</{key}>").unwrap();
348 map_state.expecting_key = false;
349 } else {
350 let entry = &map_state.entry_name.clone();
352 let value = &map_state.value_name.clone();
353 write!(self.output, "<{value}").unwrap();
354 write_xmlns_attr(&mut self.output, map_state.value_namespace.as_ref());
355 write!(self.output, ">{content}</{value}></{entry}>").unwrap();
356 map_state.expecting_key = true;
357 }
358 } else {
359 let name = if schema.xml_name().is_none() {
360 self.list_item_name
361 .clone()
362 .unwrap_or_else(|| Self::element_name(schema).to_string())
363 } else {
364 Self::element_name(schema).to_string()
365 };
366 self.open_element(&name);
369 let inherited = self.list_item_namespace.clone();
370 self.write_xmlns(schema, inherited.as_ref());
371 self.flush_start_tag();
372 self.output.push_str(content);
373 self.close_element();
374 }
375 }
376
377 fn try_write_attribute(&mut self, schema: &Schema, value: &str) -> bool {
382 use std::fmt::Write;
383 if !schema.xml_attribute() {
384 return false;
385 }
386 if let Some(Frame::StartTagPending { attrs, .. }) = self.frames.last_mut() {
392 let name = Self::element_name(schema);
393 let escaped = crate::escape::escape(value);
394 write!(attrs, " {name}=\"{escaped}\"").unwrap();
395 return true;
396 }
397 false
398 }
399
400 fn resolve_timestamp_format(&self, schema: &Schema) -> TimestampFormat {
404 schema
405 .timestamp_format()
406 .map(|t| match t.format() {
407 aws_smithy_schema::traits::TimestampFormat::EpochSeconds => {
408 TimestampFormat::EpochSeconds
409 }
410 aws_smithy_schema::traits::TimestampFormat::DateTime => TimestampFormat::DateTime,
411 aws_smithy_schema::traits::TimestampFormat::HttpDate => TimestampFormat::HttpDate,
412 })
413 .unwrap_or(self.settings.default_timestamp_format())
414 }
415}
416
417impl FinishSerializer for XmlSerializer {
418 fn finish(self) -> Vec<u8> {
419 debug_assert!(
420 self.frames.is_empty(),
421 "XmlSerializer::finish called with {} unclosed frame(s)",
422 self.frames.len()
423 );
424 self.output.into_bytes()
425 }
426}
427
428impl ShapeSerializer for XmlSerializer {
429 fn write_struct(
430 &mut self,
431 schema: &Schema,
432 value: &dyn SerializableStruct,
433 ) -> Result<(), SerdeError> {
434 if schema.xml_attribute() {
435 return Err(SerdeError::custom(
436 "@xmlAttribute is not supported on aggregate types",
437 ));
438 }
439 if !self.filter_allows(schema) {
440 return Ok(());
441 }
442 self.flush_start_tag();
443
444 let in_map_value = if let Some(map_state) = &mut self.map_state {
446 if map_state.expecting_key {
447 false
448 } else {
449 use std::fmt::Write;
454 let val_name = &map_state.value_name.clone();
455 write!(self.output, "<{val_name}>").unwrap();
456 map_state.expecting_key = true;
457 true
458 }
459 } else {
460 false
461 };
462
463 let saved_map_state = if in_map_value {
465 self.map_state.take()
466 } else {
467 None
468 };
469
470 if in_map_value {
471 let saved_filter = self.member_filter;
482 let has_attrs = schema.member_name().is_some()
488 || schema.members().iter().any(|m| m.xml_attribute());
489 if has_attrs {
490 self.member_filter = MemberFilter::AttributesOnly;
491 value.serialize_members(self)?;
492 }
493 self.member_filter = MemberFilter::NonAttributesOnly;
494 value.serialize_members(self)?;
495 self.member_filter = saved_filter;
496 use std::fmt::Write;
498 let saved = saved_map_state.as_ref().unwrap();
499 let val_name = &saved.value_name;
500 let entry = &saved.entry_name;
501 write!(self.output, "</{val_name}></{entry}>").unwrap();
502 self.map_state = saved_map_state;
503 } else {
504 let root_override = if self.frames.is_empty() {
510 self.next_root_xml_name.take()
511 } else {
512 None
513 };
514 let name = if let Some(override_name) = root_override {
515 override_name
516 } else if schema.xml_name().is_none() {
517 self.list_item_name
518 .clone()
519 .unwrap_or_else(|| Self::element_name(schema).to_string())
520 } else {
521 Self::element_name(schema).to_string()
522 };
523 let saved_list_item = self.list_item_name.take();
524 self.open_element(&name);
525 self.write_xmlns(schema, None);
526 let saved_filter = self.member_filter;
544 let has_attrs = schema.member_name().is_some()
545 || schema.members().iter().any(|m| m.xml_attribute());
546 if has_attrs {
547 self.member_filter = MemberFilter::AttributesOnly;
548 value.serialize_members(self)?;
549 }
550 self.member_filter = MemberFilter::NonAttributesOnly;
551 value.serialize_members(self)?;
552 self.member_filter = saved_filter;
553 self.close_element();
554 self.list_item_name = saved_list_item;
555 }
556 Ok(())
557 }
558
559 fn write_list(
560 &mut self,
561 schema: &Schema,
562 write_elements: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
563 ) -> Result<(), SerdeError> {
564 if schema.xml_attribute() {
565 return Err(SerdeError::custom(
566 "@xmlAttribute is not supported on aggregate types",
567 ));
568 }
569 if !self.filter_allows(schema) {
570 return Ok(());
571 }
572
573 self.flush_start_tag();
574
575 let in_map_value = if let Some(map_state) = &mut self.map_state {
577 if !map_state.expecting_key {
578 use std::fmt::Write;
579 let val_name = &map_state.value_name.clone();
580 write!(self.output, "<{val_name}>").unwrap();
581 map_state.expecting_key = true;
582 true
583 } else {
584 false
585 }
586 } else {
587 false
588 };
589 let saved_map_state = if in_map_value {
590 self.map_state.take()
591 } else {
592 None
593 };
594
595 let wrapper_name = if schema.xml_name().is_none() {
603 self.list_item_name
604 .clone()
605 .unwrap_or_else(|| Self::element_name(schema).to_string())
606 } else {
607 Self::element_name(schema).to_string()
608 };
609
610 let item_name = if schema.xml_flattened() {
620 if schema.xml_name().is_none() {
622 self.list_item_name
623 .clone()
624 .unwrap_or_else(|| Self::element_name(schema).to_string())
625 } else {
626 Self::element_name(schema).to_string()
627 }
628 } else {
629 schema
630 .member()
631 .and_then(|m| m.xml_name().map(|n| n.value().to_string()))
632 .or_else(|| {
633 schema
634 .member()
635 .and_then(|m| m.member_name().map(|s| s.to_string()))
636 })
637 .unwrap_or_else(|| "member".to_string())
638 };
639
640 let saved_list_item = self.list_item_name.take();
641 self.list_item_name = Some(item_name);
642
643 let saved_list_item_ns = self.list_item_namespace.take();
649 self.list_item_namespace = schema.member().and_then(|m| {
650 m.xml_namespace()
651 .map(|ns| (ns.uri().to_owned(), ns.prefix().map(|p| p.to_owned())))
652 });
653
654 if schema.xml_flattened() || in_map_value {
655 write_elements(self)?;
656 } else {
657 self.open_element(&wrapper_name);
658 self.write_xmlns(schema, None);
661 write_elements(self)?;
662 self.close_element();
663 }
664
665 self.list_item_name = saved_list_item;
666 self.list_item_namespace = saved_list_item_ns;
667
668 if in_map_value {
669 use std::fmt::Write;
670 let saved = saved_map_state.as_ref().unwrap();
671 let val_name = &saved.value_name;
672 let entry = &saved.entry_name;
673 write!(self.output, "</{val_name}></{entry}>").unwrap();
674 self.map_state = saved_map_state;
675 }
676 Ok(())
677 }
678
679 fn write_map(
680 &mut self,
681 schema: &Schema,
682 write_entries: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
683 ) -> Result<(), SerdeError> {
684 if schema.xml_attribute() {
685 return Err(SerdeError::custom(
686 "@xmlAttribute is not supported on aggregate types",
687 ));
688 }
689 if !self.filter_allows(schema) {
690 return Ok(());
691 }
692
693 self.flush_start_tag();
694
695 let effective_schema: &Schema = if schema.key().is_none() && schema.member().is_none() {
704 self.map_state
705 .as_ref()
706 .and_then(|s| s.value_schema)
707 .unwrap_or(schema)
708 } else {
709 schema
710 };
711 let schema = effective_schema;
712
713 let in_map_value = if let Some(map_state) = &mut self.map_state {
715 if !map_state.expecting_key {
716 use std::fmt::Write;
717 let val_name = &map_state.value_name.clone();
718 write!(self.output, "<{val_name}>").unwrap();
719 map_state.expecting_key = true;
720 true
721 } else {
722 false
723 }
724 } else {
725 false
726 };
727
728 let outer_map_state = self.map_state.take();
729
730 let entry_name = if schema.xml_flattened() {
732 Self::element_name(schema).to_string()
733 } else {
734 "entry".to_string()
735 };
736 let key_name = schema
737 .key()
738 .and_then(|k| k.xml_name().map(|n| n.value().to_string()))
739 .unwrap_or_else(|| {
740 schema
741 .key()
742 .and_then(|k| k.member_name().map(|s| s.to_string()))
743 .unwrap_or_else(|| "key".to_string())
744 });
745 let value_name = schema
746 .member()
747 .and_then(|v| v.xml_name().map(|n| n.value().to_string()))
748 .unwrap_or_else(|| {
749 schema
750 .member()
751 .and_then(|v| v.member_name().map(|s| s.to_string()))
752 .unwrap_or_else(|| "value".to_string())
753 });
754
755 self.map_state = Some(MapState {
756 entry_name,
757 key_name,
758 value_name,
759 key_namespace: schema.key().and_then(|k| {
760 k.xml_namespace()
761 .map(|ns| (ns.uri().to_owned(), ns.prefix().map(|p| p.to_owned())))
762 }),
763 value_namespace: schema.member().and_then(|v| {
764 v.xml_namespace()
765 .map(|ns| (ns.uri().to_owned(), ns.prefix().map(|p| p.to_owned())))
766 }),
767 value_schema: schema.member_static(),
771 expecting_key: true,
772 });
773
774 let wrapper_name = if schema.xml_name().is_none() {
781 self.list_item_name
782 .clone()
783 .unwrap_or_else(|| Self::element_name(schema).to_string())
784 } else {
785 Self::element_name(schema).to_string()
786 };
787
788 let saved_list_item = self.list_item_name.take();
791
792 if schema.xml_flattened() || in_map_value {
793 write_entries(self)?;
794 } else {
795 self.open_element(&wrapper_name);
796 self.write_xmlns(schema, None);
797 write_entries(self)?;
798 self.close_element();
799 }
800
801 self.list_item_name = saved_list_item;
802
803 self.map_state = outer_map_state;
804
805 if in_map_value {
806 use std::fmt::Write;
807 let saved = self.map_state.as_ref().unwrap();
808 let val_name = &saved.value_name;
809 let entry = &saved.entry_name;
810 write!(self.output, "</{val_name}></{entry}>").unwrap();
811 }
812 Ok(())
813 }
814
815 fn write_boolean(&mut self, schema: &Schema, value: bool) -> Result<(), SerdeError> {
816 self.write_safe_element(schema, if value { "true" } else { "false" });
817 Ok(())
818 }
819
820 fn write_byte(&mut self, schema: &Schema, value: i8) -> Result<(), SerdeError> {
821 self.write_safe_element(schema, &value.to_string());
822 Ok(())
823 }
824
825 fn write_short(&mut self, schema: &Schema, value: i16) -> Result<(), SerdeError> {
826 self.write_safe_element(schema, &value.to_string());
827 Ok(())
828 }
829
830 fn write_integer(&mut self, schema: &Schema, value: i32) -> Result<(), SerdeError> {
831 self.write_safe_element(schema, &value.to_string());
832 Ok(())
833 }
834
835 fn write_long(&mut self, schema: &Schema, value: i64) -> Result<(), SerdeError> {
836 self.write_safe_element(schema, &value.to_string());
837 Ok(())
838 }
839
840 fn write_float(&mut self, schema: &Schema, value: f32) -> Result<(), SerdeError> {
841 let text = if value.is_nan() {
842 "NaN".to_owned()
843 } else if value.is_infinite() {
844 if value.is_sign_positive() {
845 "Infinity".to_owned()
846 } else {
847 "-Infinity".to_owned()
848 }
849 } else {
850 value.to_string()
851 };
852 self.write_safe_element(schema, &text);
853 Ok(())
854 }
855
856 fn write_double(&mut self, schema: &Schema, value: f64) -> Result<(), SerdeError> {
857 let text = if value.is_nan() {
858 "NaN".to_owned()
859 } else if value.is_infinite() {
860 if value.is_sign_positive() {
861 "Infinity".to_owned()
862 } else {
863 "-Infinity".to_owned()
864 }
865 } else {
866 value.to_string()
867 };
868 self.write_safe_element(schema, &text);
869 Ok(())
870 }
871
872 fn write_big_integer(&mut self, schema: &Schema, value: &BigInteger) -> Result<(), SerdeError> {
873 self.write_safe_element(schema, value.as_ref());
874 Ok(())
875 }
876
877 fn write_big_decimal(&mut self, schema: &Schema, value: &BigDecimal) -> Result<(), SerdeError> {
878 self.write_safe_element(schema, value.as_ref());
879 Ok(())
880 }
881
882 fn write_string(&mut self, schema: &Schema, value: &str) -> Result<(), SerdeError> {
883 if !self.filter_allows(schema) {
884 return Ok(());
885 }
886 if self.try_write_attribute(schema, value) {
887 return Ok(());
888 }
889 use std::fmt::Write;
890 self.flush_start_tag();
891 let escaped = crate::escape::escape(value);
892 if let Some(map_state) = &mut self.map_state {
893 if map_state.expecting_key {
894 let entry = &map_state.entry_name.clone();
895 let key = &map_state.key_name.clone();
896 write!(self.output, "<{entry}><{key}").unwrap();
897 write_xmlns_attr(&mut self.output, map_state.key_namespace.as_ref());
898 write!(self.output, ">{escaped}</{key}>").unwrap();
899 map_state.expecting_key = false;
900 } else {
901 let entry = &map_state.entry_name.clone();
902 let val_name = &map_state.value_name.clone();
903 write!(self.output, "<{val_name}").unwrap();
904 write_xmlns_attr(&mut self.output, map_state.value_namespace.as_ref());
905 write!(self.output, ">{escaped}</{val_name}></{entry}>").unwrap();
906 map_state.expecting_key = true;
907 }
908 } else {
909 let name = if schema.xml_name().is_none() {
910 self.list_item_name
911 .clone()
912 .unwrap_or_else(|| Self::element_name(schema).to_string())
913 } else {
914 Self::element_name(schema).to_string()
915 };
916 self.open_element(&name);
919 let inherited = self.list_item_namespace.clone();
920 self.write_xmlns(schema, inherited.as_ref());
921 self.flush_start_tag();
922 self.output.push_str(&escaped);
923 self.close_element();
924 }
925 Ok(())
926 }
927
928 fn write_blob(&mut self, schema: &Schema, value: &[u8]) -> Result<(), SerdeError> {
929 let encoded = aws_smithy_types::base64::encode(value);
930 self.write_safe_element(schema, &encoded);
931 Ok(())
932 }
933
934 fn write_timestamp(&mut self, schema: &Schema, value: &DateTime) -> Result<(), SerdeError> {
935 let format = self.resolve_timestamp_format(schema);
936 let formatted = value
937 .fmt(format)
938 .map_err(|e| SerdeError::custom(e.to_string()))?;
939 self.write_safe_element(schema, &formatted);
941 Ok(())
942 }
943
944 fn write_document(&mut self, _schema: &Schema, _value: &Document) -> Result<(), SerdeError> {
945 Err(SerdeError::custom(
946 "document types are not supported by REST XML",
947 ))
948 }
949
950 fn write_null(&mut self, _schema: &Schema) -> Result<(), SerdeError> {
951 Ok(())
955 }
956}
957
958#[cfg(test)]
959mod tests {
960 use super::*;
961 use aws_smithy_schema::{prelude, shape_id, Schema, ShapeType};
962 use aws_smithy_types::Blob;
963
964 static NAME_MEMBER: Schema = Schema::new_member(
966 shape_id!("test", "Person$name"),
967 ShapeType::String,
968 "name",
969 0,
970 );
971 static PERSON_SCHEMA: Schema = Schema::new_struct(
972 shape_id!("test", "Person"),
973 ShapeType::Structure,
974 &[&NAME_MEMBER],
975 );
976
977 struct Person<'a> {
978 name: &'a str,
979 }
980
981 impl SerializableStruct for Person<'_> {
982 fn serialize_members(
983 &self,
984 serializer: &mut dyn ShapeSerializer,
985 ) -> Result<(), SerdeError> {
986 serializer.write_string(&NAME_MEMBER, self.name)
987 }
988 }
989
990 fn serialize<F>(write: F) -> String
991 where
992 F: FnOnce(&mut XmlSerializer) -> Result<(), SerdeError>,
993 {
994 let mut ser = XmlSerializer::new(Arc::new(XmlCodecSettings::default()));
995 write(&mut ser).expect("serialization failed");
996 String::from_utf8(<XmlSerializer as FinishSerializer>::finish(ser)).unwrap()
997 }
998
999 #[test]
1000 fn struct_with_string_member() {
1001 let p = Person { name: "Iago" };
1002 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &p));
1003 assert_eq!(out, "<Person><name>Iago</name></Person>");
1004 }
1005
1006 #[test]
1007 fn struct_with_no_members_self_closes() {
1008 struct Empty;
1009 impl SerializableStruct for Empty {
1010 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1011 Ok(())
1012 }
1013 }
1014 static EMPTY_SCHEMA: Schema =
1015 Schema::new_struct(shape_id!("test", "Empty"), ShapeType::Structure, &[]);
1016
1017 let out = serialize(|ser| ser.write_struct(&EMPTY_SCHEMA, &Empty));
1018 assert_eq!(out, "<Empty></Empty>");
1019 }
1020
1021 #[test]
1022 fn struct_string_value_is_escaped() {
1023 let p = Person { name: "<a&b>" };
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 struct_string_value_eol_is_encoded() {
1030 let p = Person { name: "a\r\nb" };
1033 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &p));
1034 assert_eq!(out, "<Person><name>a
b</name></Person>");
1035 }
1036
1037 #[test]
1038 fn nested_structs_close_correctly() {
1039 static INNER_NAME: Schema = Schema::new_member(
1045 shape_id!("test", "Inner$name"),
1046 ShapeType::String,
1047 "name",
1048 0,
1049 );
1050 static OUTER_INNER: Schema = Schema::new_member(
1051 shape_id!("test", "Outer$inner"),
1052 ShapeType::Structure,
1053 "inner",
1054 0,
1055 );
1056 static OUTER_SCHEMA: Schema = Schema::new_struct(
1057 shape_id!("test", "Outer"),
1058 ShapeType::Structure,
1059 &[&OUTER_INNER],
1060 );
1061
1062 struct Inner<'a> {
1063 name: &'a str,
1064 }
1065 impl SerializableStruct for Inner<'_> {
1066 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1067 ser.write_string(&INNER_NAME, self.name)
1068 }
1069 }
1070 struct Outer<'a> {
1071 inner: Inner<'a>,
1072 }
1073 impl SerializableStruct for Outer<'_> {
1074 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1075 ser.write_struct(&OUTER_INNER, &self.inner)
1079 }
1080 }
1081
1082 let o = Outer {
1083 inner: Inner { name: "v" },
1084 };
1085 let out = serialize(|ser| ser.write_struct(&OUTER_SCHEMA, &o));
1086 assert_eq!(out, "<Outer><inner><name>v</name></inner></Outer>");
1087 }
1088
1089 #[test]
1090 fn xml_name_overrides_member_name() {
1091 static RENAMED_MEMBER: Schema = Schema::new_member(
1092 shape_id!("test", "Person$name"),
1093 ShapeType::String,
1094 "name",
1095 0,
1096 )
1097 .with_xml_name("FullName");
1098 static PERSON_SCHEMA: Schema = Schema::new_struct(
1099 shape_id!("test", "Person"),
1100 ShapeType::Structure,
1101 &[&RENAMED_MEMBER],
1102 );
1103
1104 struct P;
1105 impl SerializableStruct for P {
1106 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1107 ser.write_string(&RENAMED_MEMBER, "v")
1108 }
1109 }
1110
1111 let out = serialize(|ser| ser.write_struct(&PERSON_SCHEMA, &P));
1112 assert_eq!(out, "<Person><FullName>v</FullName></Person>");
1113 }
1114
1115 #[test]
1116 fn original_name_overrides_id_for_synthetic_root() {
1117 static SYNTHETIC: Schema = Schema::new_struct(
1121 shape_id!("test.synthetic", "FooInput"),
1122 ShapeType::Structure,
1123 &[],
1124 )
1125 .with_original_name("FooRequest");
1126
1127 struct Empty;
1128 impl SerializableStruct for Empty {
1129 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1130 Ok(())
1131 }
1132 }
1133
1134 let out = serialize(|ser| ser.write_struct(&SYNTHETIC, &Empty));
1135 assert_eq!(out, "<FooRequest></FooRequest>");
1136 }
1137
1138 static SCALAR_MEMBER: Schema =
1141 Schema::new_member(shape_id!("test", "S$v"), ShapeType::Integer, "v", 0);
1142
1143 #[test]
1144 fn write_boolean_true() {
1145 let out = serialize(|ser| ser.write_boolean(&SCALAR_MEMBER, true));
1146 assert_eq!(out, "<v>true</v>");
1147 }
1148
1149 #[test]
1150 fn write_boolean_false() {
1151 let out = serialize(|ser| ser.write_boolean(&SCALAR_MEMBER, false));
1152 assert_eq!(out, "<v>false</v>");
1153 }
1154
1155 #[test]
1156 fn write_integer_negative() {
1157 let out = serialize(|ser| ser.write_integer(&SCALAR_MEMBER, -42));
1158 assert_eq!(out, "<v>-42</v>");
1159 }
1160
1161 #[test]
1162 fn write_long_large() {
1163 let out = serialize(|ser| ser.write_long(&SCALAR_MEMBER, i64::MAX));
1164 assert_eq!(out, format!("<v>{}</v>", i64::MAX));
1165 }
1166
1167 #[test]
1168 fn write_float_special_values() {
1169 let out = serialize(|ser| ser.write_float(&SCALAR_MEMBER, f32::NAN));
1170 assert_eq!(out, "<v>NaN</v>");
1171 let out = serialize(|ser| ser.write_float(&SCALAR_MEMBER, f32::INFINITY));
1172 assert_eq!(out, "<v>Infinity</v>");
1173 let out = serialize(|ser| ser.write_float(&SCALAR_MEMBER, f32::NEG_INFINITY));
1174 assert_eq!(out, "<v>-Infinity</v>");
1175 }
1176
1177 #[test]
1178 fn write_double_normal() {
1179 let out = serialize(|ser| ser.write_double(&SCALAR_MEMBER, 1.5));
1180 assert_eq!(out, "<v>1.5</v>");
1181 }
1182
1183 #[test]
1184 fn write_blob_base64() {
1185 let blob = Blob::new(b"hello");
1186 let out = serialize(|ser| ser.write_blob(&SCALAR_MEMBER, blob.as_ref()));
1187 assert_eq!(out, "<v>aGVsbG8=</v>");
1188 }
1189
1190 #[test]
1191 fn write_timestamp_default_datetime() {
1192 let ts = DateTime::from_secs(1515531081);
1194 let out = serialize(|ser| ser.write_timestamp(&SCALAR_MEMBER, &ts));
1195 assert_eq!(out, "<v>2018-01-09T20:51:21Z</v>");
1196 }
1197
1198 #[test]
1199 fn write_timestamp_epoch_seconds_override() {
1200 use aws_smithy_schema::traits::TimestampFormat as SchemaTimestampFormat;
1201 static TS_MEMBER: Schema =
1202 Schema::new_member(shape_id!("test", "S$t"), ShapeType::Timestamp, "t", 0)
1203 .with_timestamp_format(SchemaTimestampFormat::EpochSeconds);
1204 let ts = DateTime::from_secs(1515531081);
1205 let out = serialize(|ser| ser.write_timestamp(&TS_MEMBER, &ts));
1206 assert_eq!(out, "<t>1515531081</t>");
1207 }
1208
1209 #[test]
1210 fn write_null_emits_nothing() {
1211 let out = serialize(|ser| ser.write_null(&SCALAR_MEMBER));
1212 assert_eq!(out, "");
1213 }
1214
1215 #[test]
1218 fn attribute_string_on_struct() {
1219 static ATTR_MEMBER: Schema =
1220 Schema::new_member(shape_id!("test", "X$id"), ShapeType::String, "id", 0)
1221 .with_xml_attribute();
1222 static CHILD_MEMBER: Schema =
1223 Schema::new_member(shape_id!("test", "X$name"), ShapeType::String, "name", 1);
1224 static X_SCHEMA: Schema = Schema::new_struct(
1225 shape_id!("test", "X"),
1226 ShapeType::Structure,
1227 &[&ATTR_MEMBER, &CHILD_MEMBER],
1228 );
1229
1230 struct X;
1231 impl SerializableStruct for X {
1232 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1233 ser.write_string(&ATTR_MEMBER, "42")?;
1234 ser.write_string(&CHILD_MEMBER, "hello")
1235 }
1236 }
1237
1238 let out = serialize(|ser| ser.write_struct(&X_SCHEMA, &X));
1239 assert_eq!(out, "<X id=\"42\"><name>hello</name></X>");
1240 }
1241
1242 #[test]
1243 fn attribute_integer_on_struct() {
1244 static ATTR: Schema =
1245 Schema::new_member(shape_id!("test", "X$count"), ShapeType::Integer, "count", 0)
1246 .with_xml_attribute();
1247 static X_SCHEMA: Schema =
1248 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&ATTR]);
1249
1250 struct X;
1251 impl SerializableStruct for X {
1252 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1253 ser.write_integer(&ATTR, 7)
1254 }
1255 }
1256
1257 let out = serialize(|ser| ser.write_struct(&X_SCHEMA, &X));
1258 assert_eq!(out, "<X count=\"7\"></X>");
1259 }
1260
1261 #[test]
1262 fn attribute_value_is_escaped() {
1263 static ATTR: Schema =
1264 Schema::new_member(shape_id!("test", "X$v"), ShapeType::String, "v", 0)
1265 .with_xml_attribute();
1266 static X_SCHEMA: Schema =
1267 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&ATTR]);
1268
1269 struct X;
1270 impl SerializableStruct for X {
1271 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1272 ser.write_string(&ATTR, "a\"b&c")
1273 }
1274 }
1275
1276 let out = serialize(|ser| ser.write_struct(&X_SCHEMA, &X));
1277 assert_eq!(out, "<X v=\"a"b&c\"></X>");
1278 }
1279
1280 #[test]
1281 fn attribute_on_struct_returns_error() {
1282 static ATTR_STRUCT: Schema = Schema::new_member(
1283 shape_id!("test", "X$inner"),
1284 ShapeType::Structure,
1285 "inner",
1286 0,
1287 )
1288 .with_xml_attribute();
1289
1290 struct Empty;
1291 impl SerializableStruct for Empty {
1292 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1293 Ok(())
1294 }
1295 }
1296
1297 let mut ser = XmlSerializer::new(Arc::new(XmlCodecSettings::default()));
1298 let result = ser.write_struct(&ATTR_STRUCT, &Empty);
1299 assert!(result.is_err());
1300 }
1301
1302 #[test]
1305 fn namespace_on_struct() {
1306 static NS_SCHEMA: Schema =
1307 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[])
1308 .with_xml_namespace("https://example.com", None);
1309
1310 struct Empty;
1311 impl SerializableStruct for Empty {
1312 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1313 Ok(())
1314 }
1315 }
1316
1317 let out = serialize(|ser| ser.write_struct(&NS_SCHEMA, &Empty));
1318 assert_eq!(out, "<X xmlns=\"https://example.com\"></X>");
1319 }
1320
1321 #[test]
1322 fn namespace_with_prefix() {
1323 static NS_SCHEMA: Schema =
1324 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[])
1325 .with_xml_namespace("https://example.com", Some("ex"));
1326
1327 struct Empty;
1328 impl SerializableStruct for Empty {
1329 fn serialize_members(&self, _: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1330 Ok(())
1331 }
1332 }
1333
1334 let out = serialize(|ser| ser.write_struct(&NS_SCHEMA, &Empty));
1335 assert_eq!(out, "<X xmlns:ex=\"https://example.com\"></X>");
1336 }
1337
1338 #[test]
1339 fn namespace_with_children() {
1340 static CHILD: Schema =
1341 Schema::new_member(shape_id!("test", "X$v"), ShapeType::String, "v", 0);
1342 static NS_SCHEMA: Schema =
1343 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&CHILD])
1344 .with_xml_namespace("urn:foo", None);
1345
1346 struct X;
1347 impl SerializableStruct for X {
1348 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1349 ser.write_string(&CHILD, "hi")
1350 }
1351 }
1352
1353 let out = serialize(|ser| ser.write_struct(&NS_SCHEMA, &X));
1354 assert_eq!(out, "<X xmlns=\"urn:foo\"><v>hi</v></X>");
1355 }
1356
1357 #[test]
1360 fn list_wrapped() {
1361 static LIST_ITEM: Schema = Schema::new_member(
1364 shape_id!("test", "L$member"),
1365 ShapeType::String,
1366 "member",
1367 0,
1368 );
1369 static LIST_MEMBER: Schema =
1370 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0);
1371
1372 let out = serialize(|ser| {
1373 ser.write_list(&LIST_MEMBER, &|ser| {
1374 ser.write_string(&LIST_ITEM, "a")?;
1375 ser.write_string(&LIST_ITEM, "b")
1376 })
1377 });
1378 assert_eq!(out, "<items><member>a</member><member>b</member></items>");
1379 }
1380
1381 #[test]
1382 fn list_wrapped_with_xml_name_on_item() {
1383 static LIST_ITEM: Schema = Schema::new_member(
1385 shape_id!("test", "L$member"),
1386 ShapeType::String,
1387 "member",
1388 0,
1389 )
1390 .with_xml_name("Item");
1391 static LIST_MEMBER: Schema =
1392 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0);
1393
1394 let out = serialize(|ser| {
1395 ser.write_list(&LIST_MEMBER, &|ser| {
1396 ser.write_string(&LIST_ITEM, "a")?;
1397 ser.write_string(&LIST_ITEM, "b")
1398 })
1399 });
1400 assert_eq!(out, "<items><Item>a</Item><Item>b</Item></items>");
1401 }
1402
1403 #[test]
1404 fn list_flattened() {
1405 static LIST_ITEM: Schema = Schema::new_member(
1408 shape_id!("test", "L$member"),
1409 ShapeType::String,
1410 "member",
1411 0,
1412 )
1413 .with_xml_name("item");
1414 static LIST_MEMBER: Schema =
1415 Schema::new_member(shape_id!("test", "S$items"), ShapeType::List, "items", 0)
1416 .with_xml_flattened();
1417
1418 let out = serialize(|ser| {
1419 ser.write_list(&LIST_MEMBER, &|ser| {
1420 ser.write_string(&LIST_ITEM, "a")?;
1421 ser.write_string(&LIST_ITEM, "b")
1422 })
1423 });
1424 assert_eq!(out, "<item>a</item><item>b</item>");
1426 }
1427
1428 #[test]
1431 fn map_wrapped() {
1432 static KEY_SCHEMA: Schema =
1433 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1434 static VALUE_SCHEMA: Schema =
1435 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
1436 static MAP_MEMBER: Schema =
1437 Schema::new_member(shape_id!("test", "S$myMap"), ShapeType::Map, "myMap", 0)
1438 .with_map_members(&KEY_SCHEMA, &VALUE_SCHEMA);
1439
1440 let out = serialize(|ser| {
1441 ser.write_map(&MAP_MEMBER, &|ser| {
1442 ser.write_string(&prelude::STRING, "k1")?;
1443 ser.write_string(&prelude::STRING, "v1")?;
1444 ser.write_string(&prelude::STRING, "k2")?;
1445 ser.write_string(&prelude::STRING, "v2")
1446 })
1447 });
1448 assert_eq!(
1449 out,
1450 "<myMap><entry><key>k1</key><value>v1</value></entry><entry><key>k2</key><value>v2</value></entry></myMap>"
1451 );
1452 }
1453
1454 #[test]
1455 fn map_wrapped_with_renamed_key_value() {
1456 static REN_KEY: Schema =
1458 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0)
1459 .with_xml_name("Attribute");
1460 static REN_VALUE: Schema =
1461 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1)
1462 .with_xml_name("Setting");
1463
1464 static MAP_MEMBER: Schema =
1465 Schema::new_member(shape_id!("test", "S$m"), ShapeType::Map, "m", 0)
1466 .with_map_members(&REN_KEY, &REN_VALUE);
1467
1468 let out = serialize(|ser| {
1469 ser.write_map(&MAP_MEMBER, &|ser| {
1470 ser.write_string(&prelude::STRING, "k")?;
1471 ser.write_string(&prelude::STRING, "v")
1472 })
1473 });
1474 assert_eq!(
1475 out,
1476 "<m><entry><Attribute>k</Attribute><Setting>v</Setting></entry></m>"
1477 );
1478 }
1479
1480 #[test]
1481 fn map_flattened() {
1482 static KEY_SCHEMA: Schema =
1483 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1484 static VALUE_SCHEMA: Schema =
1485 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
1486 static MAP_MEMBER: Schema =
1487 Schema::new_member(shape_id!("test", "S$m"), ShapeType::Map, "m", 0)
1488 .with_xml_flattened()
1489 .with_map_members(&KEY_SCHEMA, &VALUE_SCHEMA);
1490
1491 let out = serialize(|ser| {
1492 ser.write_map(&MAP_MEMBER, &|ser| {
1493 ser.write_string(&prelude::STRING, "a")?;
1494 ser.write_string(&prelude::STRING, "1")?;
1495 ser.write_string(&prelude::STRING, "b")?;
1496 ser.write_string(&prelude::STRING, "2")
1497 })
1498 });
1499 assert_eq!(
1501 out,
1502 "<m><key>a</key><value>1</value></m><m><key>b</key><value>2</value></m>"
1503 );
1504 }
1505
1506 #[test]
1507 fn write_document_returns_error() {
1508 let mut ser = XmlSerializer::new(Arc::new(XmlCodecSettings::default()));
1509 let result = ser.write_document(&SCALAR_MEMBER, &Document::Object(Default::default()));
1510 assert_eq!(
1511 result.unwrap_err().to_string(),
1512 "document types are not supported by REST XML"
1513 );
1514 }
1515
1516 #[test]
1517 fn map_with_struct_value() {
1518 static HI: Schema =
1519 Schema::new_member(shape_id!("test", "G$hi"), ShapeType::String, "hi", 0);
1520 static GREETING: Schema = Schema::new_struct(
1521 shape_id!("test", "GreetingStruct"),
1522 ShapeType::Structure,
1523 &[&HI],
1524 );
1525 static KEY: Schema =
1526 Schema::new_member(shape_id!("test", "M$key"), ShapeType::String, "key", 0);
1527 static VALUE: Schema =
1528 Schema::new_member(shape_id!("test", "M$value"), ShapeType::String, "value", 1);
1529 static MAP: Schema =
1530 Schema::new_member(shape_id!("test", "S$myMap"), ShapeType::Map, "myMap", 0)
1531 .with_map_members(&KEY, &VALUE);
1532
1533 struct G;
1534 impl SerializableStruct for G {
1535 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1536 ser.write_string(&HI, "bye")
1537 }
1538 }
1539
1540 let out = serialize(|ser| {
1541 ser.write_map(&MAP, &|ser| {
1542 ser.write_string(&prelude::STRING, "baz")?;
1543 ser.write_struct(&GREETING, &G)
1544 })
1545 });
1546 assert_eq!(
1547 out,
1548 "<myMap><entry><key>baz</key><value><hi>bye</hi></value></entry></myMap>"
1549 );
1550 }
1551
1552 #[test]
1572 fn member_schema_struct_emits_attribute_member() {
1573 static ATTR_FIELD_MEMBER: Schema = Schema::new_member(
1575 shape_id!("test", "Inner$attrField"),
1576 ShapeType::String,
1577 "attrField",
1578 0,
1579 )
1580 .with_xml_name("xsi:someName")
1581 .with_xml_attribute();
1582 static INNER_TARGET: Schema = Schema::new_struct(
1583 shape_id!("test", "Inner"),
1584 ShapeType::Structure,
1585 &[&ATTR_FIELD_MEMBER],
1586 );
1587 static INNER_MEMBER: Schema = Schema::new_member(
1591 shape_id!("test", "Outer$nested"),
1592 ShapeType::Structure,
1593 "nested",
1594 0,
1595 );
1596 static OUTER_SCHEMA: Schema = Schema::new_struct(
1597 shape_id!("test", "Outer"),
1598 ShapeType::Structure,
1599 &[&INNER_MEMBER],
1600 );
1601
1602 struct Inner<'a> {
1603 attr: &'a str,
1604 }
1605 impl SerializableStruct for Inner<'_> {
1606 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1607 ser.write_string(&ATTR_FIELD_MEMBER, self.attr)
1608 }
1609 }
1610 struct Outer<'a> {
1611 inner: Inner<'a>,
1612 }
1613 impl SerializableStruct for Outer<'_> {
1614 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
1615 let _ = &INNER_TARGET;
1619 ser.write_struct(&INNER_MEMBER, &self.inner)
1620 }
1621 }
1622
1623 let outer = Outer {
1624 inner: Inner { attr: "v" },
1625 };
1626 let out = serialize(|ser| ser.write_struct(&OUTER_SCHEMA, &outer));
1627 assert_eq!(out, r#"<Outer><nested xsi:someName="v"></nested></Outer>"#);
1628 }
1629}