1use aws_smithy_schema::codec::Codec;
14use aws_smithy_types::date_time::Format as TimestampFormat;
15use std::sync::Arc;
16
17mod deserializer;
18mod serializer;
19
20pub use deserializer::{find_depth2_element_slice_by, XmlDeserializer};
21pub use serializer::XmlSerializer;
22
23#[derive(Debug)]
32pub struct XmlCodecSettings {
33 default_timestamp_format: TimestampFormat,
34 max_depth: u32,
35 enforce_strictness: bool,
36}
37
38impl XmlCodecSettings {
39 pub fn builder() -> XmlCodecSettingsBuilder {
41 XmlCodecSettingsBuilder::default()
42 }
43
44 pub fn default_timestamp_format(&self) -> TimestampFormat {
47 self.default_timestamp_format
48 }
49
50 pub fn max_depth(&self) -> u32 {
54 self.max_depth
55 }
56}
57
58impl Default for XmlCodecSettings {
59 fn default() -> Self {
60 Self {
61 default_timestamp_format: TimestampFormat::DateTime,
62 max_depth: crate::codec::deserializer::MAX_DESERIALIZE_DEPTH,
63 enforce_strictness: false,
64 }
65 }
66}
67
68#[derive(Debug, Clone)]
70pub struct XmlCodecSettingsBuilder {
71 default_timestamp_format: TimestampFormat,
72 max_depth: u32,
73 enforce_strictness: bool,
74}
75
76impl Default for XmlCodecSettingsBuilder {
77 fn default() -> Self {
78 Self {
79 default_timestamp_format: TimestampFormat::DateTime,
80 max_depth: crate::codec::deserializer::MAX_DESERIALIZE_DEPTH,
81 enforce_strictness: false,
82 }
83 }
84}
85
86impl XmlCodecSettingsBuilder {
87 pub fn enforce_strictness(mut self, value: bool) -> Self {
89 self.enforce_strictness = value;
90 self
91 }
92
93 pub fn default_timestamp_format(mut self, value: TimestampFormat) -> Self {
95 self.default_timestamp_format = value;
96 self
97 }
98
99 pub fn max_depth(mut self, value: u32) -> Self {
102 self.max_depth = value;
103 self
104 }
105
106 pub fn build(self) -> XmlCodecSettings {
108 XmlCodecSettings {
109 default_timestamp_format: self.default_timestamp_format,
110 max_depth: self.max_depth,
111 enforce_strictness: self.enforce_strictness,
112 }
113 }
114}
115
116#[derive(Debug)]
134pub struct XmlCodec {
135 settings: Arc<XmlCodecSettings>,
136}
137
138impl XmlCodec {
139 pub fn new(settings: XmlCodecSettings) -> Self {
141 Self {
142 settings: Arc::new(settings),
143 }
144 }
145
146 pub fn from_shared_settings(settings: Arc<XmlCodecSettings>) -> Self {
148 Self { settings }
149 }
150
151 pub fn settings(&self) -> &XmlCodecSettings {
153 &self.settings
154 }
155}
156
157impl Default for XmlCodec {
158 fn default() -> Self {
159 Self::new(XmlCodecSettings::default())
160 }
161}
162
163impl Codec for XmlCodec {
164 type Serializer = XmlSerializer;
165 type Deserializer<'a> = XmlDeserializer<'a>;
166
167 fn create_serializer(&self) -> Self::Serializer {
168 XmlSerializer::new(self.settings.clone())
169 }
170
171 fn create_deserializer<'a>(&self, input: &'a [u8]) -> Self::Deserializer<'a> {
172 XmlDeserializer::new(input, self.settings.clone())
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 #[test]
181 fn test_default_settings() {
182 let settings = XmlCodecSettings::default();
183 assert_eq!(
184 settings.default_timestamp_format(),
185 TimestampFormat::DateTime
186 );
187 }
188
189 #[test]
190 fn test_codec_creation() {
191 let codec = XmlCodec::default();
192 let _serializer = codec.create_serializer();
193 let _deserializer = codec.create_deserializer(b"<Root/>");
194 }
195
196 #[test]
197 fn test_end_to_end_serialize_through_codec() {
198 use aws_smithy_schema::codec::FinishSerializer;
199 use aws_smithy_schema::serde::{SerdeError, SerializableStruct, ShapeSerializer};
200 use aws_smithy_schema::{shape_id, Schema, ShapeType};
201
202 static NAME: Schema<'static> =
203 Schema::new_member(shape_id!("test", "X$name"), ShapeType::String, "name", 0);
204 static X_SCHEMA: Schema<'static> =
205 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&NAME])
206 .with_xml_namespace("urn:test", None);
207
208 struct X;
209 impl SerializableStruct for X {
210 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
211 ser.write_string(&NAME, "hello")
212 }
213 }
214
215 let codec = XmlCodec::default();
216 let mut ser = codec.create_serializer();
217 ser.write_struct(&X_SCHEMA, &X).unwrap();
218 let bytes = ser.finish();
219 assert_eq!(
220 String::from_utf8(bytes).unwrap(),
221 "<X xmlns=\"urn:test\"><name>hello</name></X>"
222 );
223 }
224
225 #[test]
226 fn test_end_to_end_deserialize_through_codec() {
227 use aws_smithy_schema::serde::ShapeDeserializer;
228 use aws_smithy_schema::{shape_id, Schema, ShapeType};
229
230 static NAME: Schema<'static> =
231 Schema::new_member(shape_id!("test", "X$name"), ShapeType::String, "name", 0);
232 static AGE: Schema<'static> =
233 Schema::new_member(shape_id!("test", "X$age"), ShapeType::Integer, "age", 1);
234 static X_SCHEMA: Schema<'static> =
235 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&NAME, &AGE]);
236
237 let codec = XmlCodec::default();
238 let xml = b"<X><name>Alice</name><age>30</age></X>";
239 let mut deser = codec.create_deserializer(xml);
240
241 let mut name = String::new();
242 let mut age = 0i32;
243 deser
244 .read_struct(&X_SCHEMA, &mut |member, d| {
245 match member.member_name().unwrap() {
246 "name" => name = d.read_string(member)?,
247 "age" => age = d.read_integer(member)?,
248 _ => {}
249 }
250 Ok(())
251 })
252 .unwrap();
253
254 assert_eq!(name, "Alice");
255 assert_eq!(age, 30);
256 }
257}