use aws_smithy_schema::codec::Codec;
use aws_smithy_types::date_time::Format as TimestampFormat;
use std::sync::Arc;
mod deserializer;
mod serializer;
pub use deserializer::{find_depth2_element_slice_by, XmlDeserializer};
pub use serializer::XmlSerializer;
#[derive(Debug)]
pub struct XmlCodecSettings {
default_timestamp_format: TimestampFormat,
max_depth: u32,
enforce_strictness: bool,
}
impl XmlCodecSettings {
pub fn builder() -> XmlCodecSettingsBuilder {
XmlCodecSettingsBuilder::default()
}
pub fn default_timestamp_format(&self) -> TimestampFormat {
self.default_timestamp_format
}
pub fn max_depth(&self) -> u32 {
self.max_depth
}
}
impl Default for XmlCodecSettings {
fn default() -> Self {
Self {
default_timestamp_format: TimestampFormat::DateTime,
max_depth: crate::codec::deserializer::MAX_DESERIALIZE_DEPTH,
enforce_strictness: false,
}
}
}
#[derive(Debug, Clone)]
pub struct XmlCodecSettingsBuilder {
default_timestamp_format: TimestampFormat,
max_depth: u32,
enforce_strictness: bool,
}
impl Default for XmlCodecSettingsBuilder {
fn default() -> Self {
Self {
default_timestamp_format: TimestampFormat::DateTime,
max_depth: crate::codec::deserializer::MAX_DESERIALIZE_DEPTH,
enforce_strictness: false,
}
}
}
impl XmlCodecSettingsBuilder {
pub fn enforce_strictness(mut self, value: bool) -> Self {
self.enforce_strictness = value;
self
}
pub fn default_timestamp_format(mut self, value: TimestampFormat) -> Self {
self.default_timestamp_format = value;
self
}
pub fn max_depth(mut self, value: u32) -> Self {
self.max_depth = value;
self
}
pub fn build(self) -> XmlCodecSettings {
XmlCodecSettings {
default_timestamp_format: self.default_timestamp_format,
max_depth: self.max_depth,
enforce_strictness: self.enforce_strictness,
}
}
}
#[derive(Debug)]
pub struct XmlCodec {
settings: Arc<XmlCodecSettings>,
}
impl XmlCodec {
pub fn new(settings: XmlCodecSettings) -> Self {
Self {
settings: Arc::new(settings),
}
}
pub fn from_shared_settings(settings: Arc<XmlCodecSettings>) -> Self {
Self { settings }
}
pub fn settings(&self) -> &XmlCodecSettings {
&self.settings
}
}
impl Default for XmlCodec {
fn default() -> Self {
Self::new(XmlCodecSettings::default())
}
}
impl Codec for XmlCodec {
type Serializer = XmlSerializer;
type Deserializer<'a> = XmlDeserializer<'a>;
fn create_serializer(&self) -> Self::Serializer {
XmlSerializer::new(self.settings.clone())
}
fn create_deserializer<'a>(&self, input: &'a [u8]) -> Self::Deserializer<'a> {
XmlDeserializer::new(input, self.settings.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_settings() {
let settings = XmlCodecSettings::default();
assert_eq!(
settings.default_timestamp_format(),
TimestampFormat::DateTime
);
}
#[test]
fn test_codec_creation() {
let codec = XmlCodec::default();
let _serializer = codec.create_serializer();
let _deserializer = codec.create_deserializer(b"<Root/>");
}
#[test]
fn test_end_to_end_serialize_through_codec() {
use aws_smithy_schema::codec::FinishSerializer;
use aws_smithy_schema::serde::{SerdeError, SerializableStruct, ShapeSerializer};
use aws_smithy_schema::{shape_id, Schema, ShapeType};
static NAME: Schema<'static> =
Schema::new_member(shape_id!("test", "X$name"), ShapeType::String, "name", 0);
static X_SCHEMA: Schema<'static> =
Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&NAME])
.with_xml_namespace("urn:test", None);
struct X;
impl SerializableStruct for X {
fn schema(&self) -> &Schema<'_> {
&X_SCHEMA
}
fn serialize_members(&self, ser: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
ser.write_string(&NAME, "hello")
}
}
let codec = XmlCodec::default();
let mut ser = codec.create_serializer();
ser.write_struct(&X_SCHEMA, &X).unwrap();
let bytes = ser.finish();
assert_eq!(
String::from_utf8(bytes).unwrap(),
"<X xmlns=\"urn:test\"><name>hello</name></X>"
);
}
#[test]
fn test_end_to_end_deserialize_through_codec() {
use aws_smithy_schema::serde::ShapeDeserializer;
use aws_smithy_schema::{shape_id, Schema, ShapeType};
static NAME: Schema<'static> =
Schema::new_member(shape_id!("test", "X$name"), ShapeType::String, "name", 0);
static AGE: Schema<'static> =
Schema::new_member(shape_id!("test", "X$age"), ShapeType::Integer, "age", 1);
static X_SCHEMA: Schema<'static> =
Schema::new_struct(shape_id!("test", "X"), ShapeType::Structure, &[&NAME, &AGE]);
let codec = XmlCodec::default();
let xml = b"<X><name>Alice</name><age>30</age></X>";
let mut deser = codec.create_deserializer(xml);
let mut name = String::new();
let mut age = 0i32;
deser
.read_struct(&X_SCHEMA, &mut |member, d| {
match member.member_name().unwrap() {
"name" => name = d.read_string(member)?,
"age" => age = d.read_integer(member)?,
_ => {}
}
Ok(())
})
.unwrap();
assert_eq!(name, "Alice");
assert_eq!(age, 30);
}
}