serialize Vec and Option<Vec>

fix #5
This commit is contained in:
Marc-Antoine Arnaud 2018-11-05 17:02:37 +01:00
parent 9cab498963
commit 96bac71db5
4 changed files with 79 additions and 39 deletions

View File

@ -85,6 +85,11 @@ fn ser_option() {
convert_and_validate!(f64, Some(-12.5 as f64), Some("-12.5")); convert_and_validate!(f64, Some(-12.5 as f64), Some("-12.5"));
convert_and_validate!(f64, None, None); convert_and_validate!(f64, None, None);
convert_and_validate!(Vec<u8>, None, None);
convert_and_validate!(Vec<u8>, Some(vec![0]), Some("0"));
convert_and_validate!(Vec<String>, None, None);
convert_and_validate!(Vec<String>, Some(vec!["test".to_string()]), Some("test"));
convert_and_validate_as_attribute!(String, Some("test".to_string()), Some("test")); convert_and_validate_as_attribute!(String, Some("test".to_string()), Some("test"));
convert_and_validate_as_attribute!(String, None, None); convert_and_validate_as_attribute!(String, None, None);
convert_and_validate_as_attribute!(bool, Some(true), Some("true")); convert_and_validate_as_attribute!(bool, Some(true), Some("true"));

View File

@ -19,8 +19,12 @@ macro_rules! convert_and_validate {
let model = Data { item: $value }; let model = Data { item: $value };
let data: Result<String, String> = to_string(&model); let data: Result<String, String> = to_string(&model);
let content = String::from("<?xml version=\"1.0\" encoding=\"utf-8\"?><data><item>") + $content let content = if $content == "" {
+ "</item></data>"; String::from("<?xml version=\"1.0\" encoding=\"utf-8\"?><data />")
} else {
String::from("<?xml version=\"1.0\" encoding=\"utf-8\"?><data><item>") + $content
+ "</item></data>"
};
assert_eq!(data, Ok(content)); assert_eq!(data, Ok(content));
}}; }};
} }
@ -60,6 +64,8 @@ fn ser_type() {
convert_and_validate!(i64, -12 as i64, "-12"); convert_and_validate!(i64, -12 as i64, "-12");
convert_and_validate!(f32, -12.5 as f32, "-12.5"); convert_and_validate!(f32, -12.5 as f32, "-12.5");
convert_and_validate!(f64, -12.5 as f64, "-12.5"); convert_and_validate!(f64, -12.5 as f64, "-12.5");
convert_and_validate!(Vec<String>, vec![], "");
convert_and_validate!(Vec<String>, vec!["test".to_string()], "test");
convert_and_validate_as_attribute!(String, "test".to_string(), "test"); convert_and_validate_as_attribute!(String, "test".to_string(), "test");
convert_and_validate_as_attribute!(bool, true, "true"); convert_and_validate_as_attribute!(bool, true, "true");

View File

@ -37,49 +37,47 @@ impl FieldType {
"f32" => Some(FieldType::FieldTypeF32), "f32" => Some(FieldType::FieldTypeF32),
"f64" => Some(FieldType::FieldTypeF64), "f64" => Some(FieldType::FieldTypeF64),
"Option" => get_sub_type(t).map(|data_type| { "Option" => get_sub_type(t).map(|data_type| {
let p = syn::PathSegment {
ident: data_type,
arguments: syn::PathArguments::None,
};
FieldType::FieldTypeOption { FieldType::FieldTypeOption {
data_type: Box::new(FieldType::from_ident(&p).unwrap()), data_type: Box::new(FieldType::from_ident(&data_type).unwrap()),
} }
}), }),
"Vec" => get_sub_type(t).map(|data_type| { "Vec" => get_sub_type(t).map(|data_type| {
let p = syn::PathSegment {
ident: data_type,
arguments: syn::PathArguments::None,
};
FieldType::FieldTypeVec { FieldType::FieldTypeVec {
data_type: Box::new(FieldType::from_ident(&p).unwrap()), data_type: Box::new(FieldType::from_ident(&data_type).unwrap()),
} }
}), }),
_struct_name => Some(FieldType::FieldTypeStruct { _struct_name => {
Some(FieldType::FieldTypeStruct {
struct_name: t.ident.clone(), struct_name: t.ident.clone(),
}), })},
} }
} }
} }
pub fn get_field_type(field: &syn::Field) -> Option<FieldType> { pub fn get_field_type(field: &syn::Field) -> Option<FieldType> {
match field.ty { match field.ty {
Path(ref path) => match path.path.segments.first() { Path(ref path) => {
if path.path.segments.len() != 1 {
return None;
}
match path.path.segments.first() {
Some(Pair::End(t)) => FieldType::from_ident(t), Some(Pair::End(t)) => FieldType::from_ident(t),
_ => None, _ => {
None
},
}
}, },
_ => None, _ => None,
} }
} }
fn get_sub_type(t: &syn::PathSegment) -> Option<syn::Ident> { fn get_sub_type(t: &syn::PathSegment) -> Option<syn::PathSegment> {
if let syn::PathArguments::AngleBracketed(ref args) = t.arguments { if let syn::PathArguments::AngleBracketed(ref args) = t.arguments {
if let Some(Pair::End(tt)) = args.args.first() { if let Some(Pair::End(tt)) = args.args.first() {
if let syn::GenericArgument::Type(ref argument) = *tt { if let syn::GenericArgument::Type(ref argument) = *tt {
if let Path(ref path2) = *argument { if let Path(ref path2) = *argument {
if let Some(Pair::End(ttt)) = path2.path.segments.first() { if let Some(Pair::End(ttt)) = path2.path.segments.first() {
return Some(ttt.ident.clone()); return Some(ttt.clone());
} }
} }
} }

View File

@ -23,14 +23,14 @@ pub fn serialize(
} }
let renamed_label = match field_attrs.rename { let renamed_label = match field_attrs.rename {
Some(value) => Some(Ident::new(&format!("{}", value), Span::call_site())), Some(value) => Ident::new(&format!("{}", value), Span::call_site()),
None => field.ident.clone(), None => field.ident.clone().unwrap(),
}; };
let label = &field.ident; let label = &field.ident;
let label_name = if let Some(prefix) = field_attrs.prefix { let label_name = if let Some(prefix) = field_attrs.prefix {
prefix + ":" + renamed_label.unwrap().to_string().as_ref() prefix + ":" + renamed_label.to_string().as_ref()
} else { } else {
renamed_label.unwrap().to_string() renamed_label.to_string()
}; };
match get_field_type(field) { match get_field_type(field) {
@ -93,6 +93,20 @@ pub fn serialize(
struct_start_event struct_start_event
}; };
}), }),
Some(&FieldType::FieldTypeVec{..}) => {
Some(quote!{
for item in &self.#label {
let start_event = XmlEvent::start_element(#label_name);
let _ret = writer.write(start_event);
let data_event = XmlEvent::characters(item);
let _ret = writer.write(data_event);
let end_event = XmlEvent::end_element();
let _ret = writer.write(end_event);
}
})
}
_ => None, _ => None,
} }
} }
@ -153,14 +167,14 @@ pub fn serialize(
} }
let renamed_label = match field_attrs.rename { let renamed_label = match field_attrs.rename {
Some(value) => Some(Ident::new(&format!("{}", value), Span::call_site())), Some(value) => Ident::new(&format!("{}", value), Span::call_site()),
None => field.ident.clone(), None => field.ident.clone().unwrap(),
}; };
let label_name = if let Some(prefix) = field_attrs.prefix { let label_name = if let Some(prefix) = field_attrs.prefix {
prefix + ":" + renamed_label.unwrap().to_string().as_ref() prefix + ":" + renamed_label.to_string().as_ref()
} else { } else {
renamed_label.unwrap().to_string() renamed_label.to_string()
}; };
match get_field_type(field) { match get_field_type(field) {
@ -233,10 +247,26 @@ pub fn serialize(
let _ret = writer.write(end_event); let _ret = writer.write(end_event);
} }
}), }),
Some(&FieldType::FieldTypeVec{ .. }) => Some(quote!{
if let Some(ref items) = &self.#label {
for item in items.iter() {
let start_event = XmlEvent::start_element(#label_name);
let _ret = writer.write(start_event);
let value = format!("{}", item);
let data_event = XmlEvent::characters(&value);
let _ret = writer.write(data_event);
let end_event = XmlEvent::end_element();
let _ret = writer.write(end_event);
}
}
}),
_ => None, _ => None,
} }
} }
Some(FieldType::FieldTypeStruct { .. }) => Some(quote!{ Some(FieldType::FieldTypeStruct { .. }) => {
Some(quote!{
writer.set_skip_start_end(false); writer.set_skip_start_end(false);
match self.#label.serialize(writer) { match self.#label.serialize(writer) {
Ok(()) => {}, Ok(()) => {},
@ -244,7 +274,8 @@ pub fn serialize(
return Err(msg); return Err(msg);
}, },
}; };
}), })
},
Some(FieldType::FieldTypeVec { data_type }) => { Some(FieldType::FieldTypeVec { data_type }) => {
let dt = Box::into_raw(data_type); let dt = Box::into_raw(data_type);
match unsafe { dt.as_ref() } { match unsafe { dt.as_ref() } {
@ -313,7 +344,7 @@ pub fn serialize(
unimplemented!(); unimplemented!();
} }
} }
} },
None => None, None => None,
} }
}) })