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 validate_document: bool,
36 validate_root_name: bool,
37 strict_collection_element_names: bool,
38 error_root_name: Option<&'static str>,
39}
40
41impl XmlCodecSettings {
42 pub fn builder() -> XmlCodecSettingsBuilder {
44 XmlCodecSettingsBuilder::default()
45 }
46
47 pub fn default_timestamp_format(&self) -> TimestampFormat {
50 self.default_timestamp_format
51 }
52
53 pub fn max_depth(&self) -> u32 {
57 self.max_depth
58 }
59
60 pub fn strict_collection_element_names(&self) -> bool {
64 self.strict_collection_element_names
65 }
66}
67
68impl Default for XmlCodecSettings {
69 fn default() -> Self {
70 Self {
71 default_timestamp_format: TimestampFormat::DateTime,
72 max_depth: crate::codec::deserializer::MAX_DESERIALIZE_DEPTH,
73 validate_document: false,
74 validate_root_name: false,
75 strict_collection_element_names: false,
76 error_root_name: None,
77 }
78 }
79}
80
81#[derive(Debug, Clone)]
83pub struct XmlCodecSettingsBuilder {
84 default_timestamp_format: TimestampFormat,
85 max_depth: u32,
86 validate_document: bool,
87 validate_root_name: bool,
88 strict_collection_element_names: bool,
89 error_root_name: Option<&'static str>,
90}
91
92impl Default for XmlCodecSettingsBuilder {
93 fn default() -> Self {
94 Self {
95 default_timestamp_format: TimestampFormat::DateTime,
96 max_depth: crate::codec::deserializer::MAX_DESERIALIZE_DEPTH,
97 validate_document: false,
98 validate_root_name: false,
99 strict_collection_element_names: false,
100 error_root_name: None,
101 }
102 }
103}
104
105impl XmlCodecSettingsBuilder {
106 pub fn enforce_strictness(mut self, value: bool) -> Self {
109 self.validate_document = value;
110 self.validate_root_name = value;
111 self
112 }
113
114 pub fn validate_document(mut self, value: bool) -> Self {
121 self.validate_document = value;
122 self
123 }
124
125 pub fn validate_root_name(mut self, value: bool) -> Self {
127 self.validate_root_name = value;
128 self
129 }
130
131 pub fn strict_collection_element_names(mut self, value: bool) -> Self {
139 self.strict_collection_element_names = value;
140 self
141 }
142
143 pub fn error_root_name(mut self, name: &'static str) -> Self {
145 self.error_root_name = Some(name);
146 self
147 }
148
149 pub fn default_timestamp_format(mut self, value: TimestampFormat) -> Self {
151 self.default_timestamp_format = value;
152 self
153 }
154
155 pub fn max_depth(mut self, value: u32) -> Self {
158 self.max_depth = value;
159 self
160 }
161
162 pub fn build(self) -> XmlCodecSettings {
164 XmlCodecSettings {
165 default_timestamp_format: self.default_timestamp_format,
166 max_depth: self.max_depth,
167 validate_document: self.validate_document,
168 validate_root_name: self.validate_root_name,
169 strict_collection_element_names: self.strict_collection_element_names,
170 error_root_name: self.error_root_name,
171 }
172 }
173}
174
175#[derive(Debug)]
193pub struct XmlCodec {
194 settings: Arc<XmlCodecSettings>,
195}
196
197impl XmlCodec {
198 pub fn new(settings: XmlCodecSettings) -> Self {
200 Self {
201 settings: Arc::new(settings),
202 }
203 }
204
205 pub fn from_shared_settings(settings: Arc<XmlCodecSettings>) -> Self {
207 Self { settings }
208 }
209
210 pub fn settings(&self) -> &XmlCodecSettings {
212 &self.settings
213 }
214}
215
216impl Default for XmlCodec {
217 fn default() -> Self {
218 Self::new(XmlCodecSettings::default())
219 }
220}
221
222impl Codec for XmlCodec {
223 type Serializer = XmlSerializer;
224 type Deserializer<'a> = XmlDeserializer<'a>;
225
226 fn create_serializer(&self) -> Self::Serializer {
227 XmlSerializer::new(self.settings.clone())
228 }
229
230 fn create_deserializer<'a>(&self, input: &'a [u8]) -> Self::Deserializer<'a> {
231 XmlDeserializer::new(input, self.settings.clone())
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238
239 #[test]
240 fn test_default_settings() {
241 let settings = XmlCodecSettings::default();
242 assert_eq!(
243 settings.default_timestamp_format(),
244 TimestampFormat::DateTime
245 );
246 }
247
248 #[test]
249 fn test_codec_creation() {
250 let codec = XmlCodec::default();
251 let _serializer = codec.create_serializer();
252 let _deserializer = codec.create_deserializer(b"<Root/>");
253 }
254
255 #[test]
256 fn test_end_to_end_serialize_through_codec() {
257 use aws_smithy_schema::codec::FinishSerializer;
258 use aws_smithy_schema::serde::{SerdeError, SerializableStruct, ShapeSerializer};
259 use aws_smithy_schema::{shape_id, Schema, ShapeType};
260
261 static NAME: Schema<'static> =
262 Schema::new_member(shape_id!("test", "X$name"), ShapeType::String, "name", 0);
263 static X_SCHEMA: Schema<'static> =
264 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&NAME])
265 .with_xml_namespace("urn:test", None);
266
267 struct X;
268 impl SerializableStruct for X {
269 fn schema(&self) -> &Schema<'_> {
270 &X_SCHEMA
271 }
272
273 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
274 ser.write_string(&NAME, "hello")
275 }
276 }
277
278 let codec = XmlCodec::default();
279 let mut ser = codec.create_serializer();
280 ser.write_struct(&X_SCHEMA, &X).unwrap();
281 let bytes = ser.finish();
282 assert_eq!(
283 String::from_utf8(bytes).unwrap(),
284 "<X xmlns=\"urn:test\"><name>hello</name></X>"
285 );
286 }
287
288 #[test]
289 fn test_end_to_end_deserialize_through_codec() {
290 use aws_smithy_schema::serde::ShapeDeserializer;
291 use aws_smithy_schema::{shape_id, Schema, ShapeType};
292
293 static NAME: Schema<'static> =
294 Schema::new_member(shape_id!("test", "X$name"), ShapeType::String, "name", 0);
295 static AGE: Schema<'static> =
296 Schema::new_member(shape_id!("test", "X$age"), ShapeType::Integer, "age", 1);
297 static X_SCHEMA: Schema<'static> =
298 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&NAME, &AGE]);
299
300 let codec = XmlCodec::default();
301 let xml = b"<X><name>Alice</name><age>30</age></X>";
302 let mut deser = codec.create_deserializer(xml);
303
304 let mut name = String::new();
305 let mut age = 0i32;
306 deser
307 .read_struct(&X_SCHEMA, &mut |member, d| {
308 match member.member_name().unwrap() {
309 "name" => name = d.read_string(member)?,
310 "age" => age = d.read_integer(member)?,
311 _ => {}
312 }
313 Ok(())
314 })
315 .unwrap();
316
317 assert_eq!(name, "Alice");
318 assert_eq!(age, 30);
319 }
320}