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}
36
37impl XmlCodecSettings {
38 pub fn builder() -> XmlCodecSettingsBuilder {
40 XmlCodecSettingsBuilder::default()
41 }
42
43 pub fn default_timestamp_format(&self) -> TimestampFormat {
46 self.default_timestamp_format
47 }
48
49 pub fn max_depth(&self) -> u32 {
53 self.max_depth
54 }
55}
56
57impl Default for XmlCodecSettings {
58 fn default() -> Self {
59 Self {
60 default_timestamp_format: TimestampFormat::DateTime,
61 max_depth: crate::codec::deserializer::MAX_DESERIALIZE_DEPTH,
62 }
63 }
64}
65
66#[derive(Debug, Clone)]
68pub struct XmlCodecSettingsBuilder {
69 default_timestamp_format: TimestampFormat,
70 max_depth: u32,
71}
72
73impl Default for XmlCodecSettingsBuilder {
74 fn default() -> Self {
75 Self {
76 default_timestamp_format: TimestampFormat::DateTime,
77 max_depth: crate::codec::deserializer::MAX_DESERIALIZE_DEPTH,
78 }
79 }
80}
81
82impl XmlCodecSettingsBuilder {
83 pub fn default_timestamp_format(mut self, value: TimestampFormat) -> Self {
85 self.default_timestamp_format = value;
86 self
87 }
88
89 pub fn max_depth(mut self, value: u32) -> Self {
92 self.max_depth = value;
93 self
94 }
95
96 pub fn build(self) -> XmlCodecSettings {
98 XmlCodecSettings {
99 default_timestamp_format: self.default_timestamp_format,
100 max_depth: self.max_depth,
101 }
102 }
103}
104
105#[derive(Debug)]
123pub struct XmlCodec {
124 settings: Arc<XmlCodecSettings>,
125}
126
127impl XmlCodec {
128 pub fn new(settings: XmlCodecSettings) -> Self {
130 Self {
131 settings: Arc::new(settings),
132 }
133 }
134
135 pub fn from_shared_settings(settings: Arc<XmlCodecSettings>) -> Self {
137 Self { settings }
138 }
139
140 pub fn settings(&self) -> &XmlCodecSettings {
142 &self.settings
143 }
144}
145
146impl Default for XmlCodec {
147 fn default() -> Self {
148 Self::new(XmlCodecSettings::default())
149 }
150}
151
152impl Codec for XmlCodec {
153 type Serializer = XmlSerializer;
154 type Deserializer<'a> = XmlDeserializer<'a>;
155
156 fn create_serializer(&self) -> Self::Serializer {
157 XmlSerializer::new(self.settings.clone())
158 }
159
160 fn create_deserializer<'a>(&self, input: &'a [u8]) -> Self::Deserializer<'a> {
161 XmlDeserializer::new(input, self.settings.clone())
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn test_default_settings() {
171 let settings = XmlCodecSettings::default();
172 assert_eq!(
173 settings.default_timestamp_format(),
174 TimestampFormat::DateTime
175 );
176 }
177
178 #[test]
179 fn test_codec_creation() {
180 let codec = XmlCodec::default();
181 let _serializer = codec.create_serializer();
182 let _deserializer = codec.create_deserializer(b"<Root/>");
183 }
184
185 #[test]
186 fn test_end_to_end_serialize_through_codec() {
187 use aws_smithy_schema::codec::FinishSerializer;
188 use aws_smithy_schema::serde::{SerdeError, SerializableStruct, ShapeSerializer};
189 use aws_smithy_schema::{shape_id, Schema, ShapeType};
190
191 static NAME: Schema =
192 Schema::new_member(shape_id!("test", "X$name"), ShapeType::String, "name", 0);
193 static X_SCHEMA: Schema =
194 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&NAME])
195 .with_xml_namespace("urn:test", None);
196
197 struct X;
198 impl SerializableStruct for X {
199 fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
200 ser.write_string(&NAME, "hello")
201 }
202 }
203
204 let codec = XmlCodec::default();
205 let mut ser = codec.create_serializer();
206 ser.write_struct(&X_SCHEMA, &X).unwrap();
207 let bytes = ser.finish();
208 assert_eq!(
209 String::from_utf8(bytes).unwrap(),
210 "<X xmlns=\"urn:test\"><name>hello</name></X>"
211 );
212 }
213
214 #[test]
215 fn test_end_to_end_deserialize_through_codec() {
216 use aws_smithy_schema::serde::ShapeDeserializer;
217 use aws_smithy_schema::{shape_id, Schema, ShapeType};
218
219 static NAME: Schema =
220 Schema::new_member(shape_id!("test", "X$name"), ShapeType::String, "name", 0);
221 static AGE: Schema =
222 Schema::new_member(shape_id!("test", "X$age"), ShapeType::Integer, "age", 1);
223 static X_SCHEMA: Schema =
224 Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&NAME, &AGE]);
225
226 let codec = XmlCodec::default();
227 let xml = b"<X><name>Alice</name><age>30</age></X>";
228 let mut deser = codec.create_deserializer(xml);
229
230 let mut name = String::new();
231 let mut age = 0i32;
232 deser
233 .read_struct(&X_SCHEMA, &mut |member, d| {
234 match member.member_name().unwrap() {
235 "name" => name = d.read_string(member)?,
236 "age" => age = d.read_integer(member)?,
237 _ => {}
238 }
239 Ok(())
240 })
241 .unwrap();
242
243 assert_eq!(name, "Alice");
244 assert_eq!(age, 30);
245 }
246}