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 schema(&self) -> &Schema<'_> {
211 &X_SCHEMA
212 }
213
214 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
215 ser.write_string(&NAME, "hello")
216 }
217 }
218
219 let codec = XmlCodec::default();
220 let mut ser = codec.create_serializer();
221 ser.write_struct(&X_SCHEMA, &X).unwrap();
222 let bytes = ser.finish();
223 assert_eq!(
224 String::from_utf8(bytes).unwrap(),
225 "<X xmlns=\"urn:test\"><name>hello</name></X>"
226 );
227 }
228
229 #[test]
230 fn test_end_to_end_deserialize_through_codec() {
231 use aws_smithy_schema::serde::ShapeDeserializer;
232 use aws_smithy_schema::{shape_id, Schema, ShapeType};
233
234 static NAME: Schema<'static> =
235 Schema::new_member(shape_id!("test", "X$name"), ShapeType::String, "name", 0);
236 static AGE: Schema<'static> =
237 Schema::new_member(shape_id!("test", "X$age"), ShapeType::Integer, "age", 1);
238 static X_SCHEMA: Schema<'static> =
239 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&NAME, &AGE]);
240
241 let codec = XmlCodec::default();
242 let xml = b"<X><name>Alice</name><age>30</age></X>";
243 let mut deser = codec.create_deserializer(xml);
244
245 let mut name = String::new();
246 let mut age = 0i32;
247 deser
248 .read_struct(&X_SCHEMA, &mut |member, d| {
249 match member.member_name().unwrap() {
250 "name" => name = d.read_string(member)?,
251 "age" => age = d.read_integer(member)?,
252 _ => {}
253 }
254 Ok(())
255 })
256 .unwrap();
257
258 assert_eq!(name, "Alice");
259 assert_eq!(age, 30);
260 }
261}