support Option type value

This commit is contained in:
Marc-Antoine Arnaud
2018-05-29 16:20:18 +02:00
parent ef37615458
commit 266b77428b
8 changed files with 714 additions and 47 deletions

View File

@@ -66,6 +66,10 @@ pub fn parse(
#[allow(unused_mut)]
let mut #field_label : #struct_name = #struct_name::default();
}),
Some(FieldType::FieldTypeOption { .. }) => Some(quote!{
#[allow(unused_mut)]
let mut #field_label = None;
}),
Some(FieldType::FieldTypeVec { data_type }) => {
let dt = Box::into_raw(data_type);
match unsafe { dt.as_ref() } {
@@ -109,7 +113,8 @@ pub fn parse(
#[allow(unused_mut)]
let mut #field_label : Vec<#struct_name> = vec![];
}),
Some(&FieldType::FieldTypeVec { .. }) => {
Some(&FieldType::FieldTypeOption { .. })
| Some(&FieldType::FieldTypeVec { .. }) => {
unimplemented!();
}
None => {

View File

@@ -62,6 +62,10 @@ pub fn parse(
#[allow(unused_mut, non_snake_case, non_camel_case_types)]
let mut #label : #struct_name = #struct_name::default();
}),
Some(FieldType::FieldTypeOption { .. }) => Some(quote!{
#[allow(unused_mut, non_snake_case, non_camel_case_types)]
let mut #label = None;
}),
Some(FieldType::FieldTypeVec { data_type }) => {
let dt = Box::into_raw(data_type);
match unsafe { dt.as_ref() } {
@@ -105,7 +109,7 @@ pub fn parse(
#[allow(unused_mut)]
let mut #label : Vec<#struct_name> = vec![];
}),
Some(&FieldType::FieldTypeVec { .. }) => {
Some(&FieldType::FieldTypeOption { .. }) | Some(&FieldType::FieldTypeVec { .. }) => {
unimplemented!();
}
None => {
@@ -194,6 +198,50 @@ pub fn parse(
}
})
}
Some(FieldType::FieldTypeOption { data_type }) => {
let dt = Box::into_raw(data_type);
match unsafe { dt.as_ref() } {
Some(&FieldType::FieldTypeString) => {
build_declare_visitor(&quote!{String}, &quote!{visit_str}, &visitor_label)
}
Some(&FieldType::FieldTypeBool) => {
build_declare_visitor(&quote!{bool}, &quote!{visit_bool}, &visitor_label)
}
Some(&FieldType::FieldTypeI8) => {
build_declare_visitor(&quote!{i8}, &quote!{visit_i8}, &visitor_label)
}
Some(&FieldType::FieldTypeU8) => {
build_declare_visitor(&quote!{u8}, &quote!{visit_u8}, &visitor_label)
}
Some(&FieldType::FieldTypeI16) => {
build_declare_visitor(&quote!{i16}, &quote!{visit_i16}, &visitor_label)
}
Some(&FieldType::FieldTypeU16) => {
build_declare_visitor(&quote!{u16}, &quote!{visit_u16}, &visitor_label)
}
Some(&FieldType::FieldTypeI32) => {
build_declare_visitor(&quote!{i32}, &quote!{visit_i32}, &visitor_label)
}
Some(&FieldType::FieldTypeU32) => {
build_declare_visitor(&quote!{u32}, &quote!{visit_u32}, &visitor_label)
}
Some(&FieldType::FieldTypeI64) => {
build_declare_visitor(&quote!{i64}, &quote!{visit_i64}, &visitor_label)
}
Some(&FieldType::FieldTypeU64) => {
build_declare_visitor(&quote!{u64}, &quote!{visit_u64}, &visitor_label)
}
Some(&FieldType::FieldTypeF32) => {
build_declare_visitor(&quote!{f32}, &quote!{visit_f32}, &visitor_label)
}
Some(&FieldType::FieldTypeF64) => {
build_declare_visitor(&quote!{f64}, &quote!{visit_f64}, &visitor_label)
}
_ => {
unimplemented!();
}
}
}
Some(FieldType::FieldTypeVec { data_type }) => {
let dt = Box::into_raw(data_type);
match unsafe { dt.as_ref() } {
@@ -422,6 +470,144 @@ pub fn parse(
}
}
}),
Some(FieldType::FieldTypeOption { data_type }) => {
let dt = Box::into_raw(data_type);
match unsafe { dt.as_ref() } {
Some(&FieldType::FieldTypeString) => {
let visitor = Ident::new("visit_str", Span::call_site());
build_call_visitor(
&quote!{String},
&visitor,
&quote!{= Some(value)},
&visitor_label,
label,
&label_name,
)
}
Some(&FieldType::FieldTypeBool) => {
let visitor = Ident::new("visit_bool", Span::call_site());
build_call_visitor(
&quote!{bool},
&visitor,
&quote!{= Some(value)},
&visitor_label,
label,
&label_name,
)
}
Some(&FieldType::FieldTypeU8) => {
let visitor = Ident::new("visit_u8", Span::call_site());
build_call_visitor(
&quote!{u8},
&visitor,
&quote!{= Some(value)},
&visitor_label,
label,
&label_name,
)
}
Some(&FieldType::FieldTypeI8) => {
let visitor = Ident::new("visit_i8", Span::call_site());
build_call_visitor(
&quote!{i8},
&visitor,
&quote!{= Some(value)},
&visitor_label,
label,
&label_name,
)
}
Some(&FieldType::FieldTypeU16) => {
let visitor = Ident::new("visit_u16", Span::call_site());
build_call_visitor(
&quote!{u16},
&visitor,
&quote!{= Some(value)},
&visitor_label,
label,
&label_name,
)
}
Some(&FieldType::FieldTypeI16) => {
let visitor = Ident::new("visit_i16", Span::call_site());
build_call_visitor(
&quote!{i16},
&visitor,
&quote!{= Some(value)},
&visitor_label,
label,
&label_name,
)
}
Some(&FieldType::FieldTypeU32) => {
let visitor = Ident::new("visit_u32", Span::call_site());
build_call_visitor(
&quote!{u32},
&visitor,
&quote!{= Some(value)},
&visitor_label,
label,
&label_name,
)
}
Some(&FieldType::FieldTypeI32) => {
let visitor = Ident::new("visit_i32", Span::call_site());
build_call_visitor(
&quote!{i32},
&visitor,
&quote!{= Some(value)},
&visitor_label,
label,
&label_name,
)
}
Some(&FieldType::FieldTypeU64) => {
let visitor = Ident::new("visit_u64", Span::call_site());
build_call_visitor(
&quote!{u64},
&visitor,
&quote!{= Some(value)},
&visitor_label,
label,
&label_name,
)
}
Some(&FieldType::FieldTypeI64) => {
let visitor = Ident::new("visit_i64", Span::call_site());
build_call_visitor(
&quote!{i64},
&visitor,
&quote!{= Some(value)},
&visitor_label,
label,
&label_name,
)
}
Some(&FieldType::FieldTypeF32) => {
let visitor = Ident::new("visit_f32", Span::call_site());
build_call_visitor(
&quote!{f32},
&visitor,
&quote!{= Some(value)},
&visitor_label,
label,
&label_name,
)
}
Some(&FieldType::FieldTypeF64) => {
let visitor = Ident::new("visit_f64", Span::call_site());
build_call_visitor(
&quote!{f64},
&visitor,
&quote!{= Some(value)},
&visitor_label,
label,
&label_name,
)
}
_ => None,
}
}
Some(FieldType::FieldTypeVec { data_type }) => {
let dt = Box::into_raw(data_type);
match unsafe { dt.as_ref() } {
@@ -613,40 +799,173 @@ pub fn parse(
}
}
}),
Some(FieldType::FieldTypeBool) => {
build_call_visitor_for_attribute(label, &label_name, &quote!{visit_bool}, &visitor_label)
Some(FieldType::FieldTypeBool) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= value},
&quote!{visit_bool},
&visitor_label,
),
Some(FieldType::FieldTypeI8) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= value},
&quote!{visit_i8},
&visitor_label,
),
Some(FieldType::FieldTypeU8) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= value},
&quote!{visit_u8},
&visitor_label,
),
Some(FieldType::FieldTypeI16) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= value},
&quote!{visit_i16},
&visitor_label,
),
Some(FieldType::FieldTypeU16) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= value},
&quote!{visit_u16},
&visitor_label,
),
Some(FieldType::FieldTypeI32) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= value},
&quote!{visit_i32},
&visitor_label,
),
Some(FieldType::FieldTypeU32) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= value},
&quote!{visit_u32},
&visitor_label,
),
Some(FieldType::FieldTypeI64) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= value},
&quote!{visit_i64},
&visitor_label,
),
Some(FieldType::FieldTypeU64) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= value},
&quote!{visit_u64},
&visitor_label,
),
Some(FieldType::FieldTypeF32) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= value},
&quote!{visit_f32},
&visitor_label,
),
Some(FieldType::FieldTypeF64) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= value},
&quote!{visit_f64},
&visitor_label,
),
Some(FieldType::FieldTypeOption { data_type }) => {
let dt = Box::into_raw(data_type);
match unsafe { dt.as_ref() } {
Some(&FieldType::FieldTypeString) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= Some(value)},
&quote!{visit_str},
&visitor_label,
),
Some(&FieldType::FieldTypeBool) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= Some(value)},
&quote!{visit_bool},
&visitor_label,
),
Some(&FieldType::FieldTypeU8) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= Some(value)},
&quote!{visit_u8},
&visitor_label,
),
Some(&FieldType::FieldTypeI8) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= Some(value)},
&quote!{visit_i8},
&visitor_label,
),
Some(&FieldType::FieldTypeU16) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= Some(value)},
&quote!{visit_u16},
&visitor_label,
),
Some(&FieldType::FieldTypeI16) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= Some(value)},
&quote!{visit_i16},
&visitor_label,
),
Some(&FieldType::FieldTypeU32) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= Some(value)},
&quote!{visit_u32},
&visitor_label,
),
Some(&FieldType::FieldTypeI32) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= Some(value)},
&quote!{visit_i32},
&visitor_label,
),
Some(&FieldType::FieldTypeU64) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= Some(value)},
&quote!{visit_u64},
&visitor_label,
),
Some(&FieldType::FieldTypeI64) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= Some(value)},
&quote!{visit_i64},
&visitor_label,
),
Some(&FieldType::FieldTypeF32) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= Some(value)},
&quote!{visit_f32},
&visitor_label,
),
Some(&FieldType::FieldTypeF64) => build_call_visitor_for_attribute(
label,
&label_name,
&quote!{= Some(value)},
&quote!{visit_f64},
&visitor_label,
),
_ => None,
}
}
Some(FieldType::FieldTypeI8) => {
build_call_visitor_for_attribute(label, &label_name, &quote!{visit_i8}, &visitor_label)
}
Some(FieldType::FieldTypeU8) => {
build_call_visitor_for_attribute(label, &label_name, &quote!{visit_u8}, &visitor_label)
}
Some(FieldType::FieldTypeI16) => {
build_call_visitor_for_attribute(label, &label_name, &quote!{visit_i16}, &visitor_label)
}
Some(FieldType::FieldTypeU16) => {
build_call_visitor_for_attribute(label, &label_name, &quote!{visit_u16}, &visitor_label)
}
Some(FieldType::FieldTypeI32) => {
build_call_visitor_for_attribute(label, &label_name, &quote!{visit_i32}, &visitor_label)
}
Some(FieldType::FieldTypeU32) => {
build_call_visitor_for_attribute(label, &label_name, &quote!{visit_u32}, &visitor_label)
}
Some(FieldType::FieldTypeI64) => {
build_call_visitor_for_attribute(label, &label_name, &quote!{visit_i64}, &visitor_label)
}
Some(FieldType::FieldTypeU64) => {
build_call_visitor_for_attribute(label, &label_name, &quote!{visit_u64}, &visitor_label)
}
Some(FieldType::FieldTypeF32) => {
build_call_visitor_for_attribute(label, &label_name, &quote!{visit_f32}, &visitor_label)
}
Some(FieldType::FieldTypeF64) => {
build_call_visitor_for_attribute(label, &label_name, &quote!{visit_f64}, &visitor_label)
}
Some(FieldType::FieldTypeStruct { struct_name }) => {
let struct_ident = Ident::new(
&format!("__Visitor_{}_{}", label_name, struct_name),
@@ -742,9 +1061,10 @@ pub fn parse(
&quote!{f64::from_str(text_content).unwrap()},
),
Some(FieldType::FieldTypeStruct { .. }) | Some(FieldType::FieldTypeVec { .. }) | None => {
None
}
Some(FieldType::FieldTypeStruct { .. })
| Some(FieldType::FieldTypeOption { .. })
| Some(FieldType::FieldTypeVec { .. })
| None => None,
}
})
.filter(|x| x.is_some())
@@ -900,6 +1220,7 @@ fn build_call_visitor(
fn build_call_visitor_for_attribute(
label: &Option<Ident>,
label_name: &str,
action: &TokenStream,
visitor: &TokenStream,
visitor_label: &Ident,
) -> Option<TokenStream> {
@@ -908,7 +1229,7 @@ fn build_call_visitor_for_attribute(
if attr.name.local_name == #label_name {
let visitor = #visitor_label{};
match visitor.#visitor(&attr.value) {
Ok(value) => {#label = value;}
Ok(value) => {#label #action;}
Err(msg) => {return Err(msg);}
}
}

View File

@@ -16,6 +16,7 @@ pub enum FieldType {
FieldTypeU64,
FieldTypeF32,
FieldTypeF64,
FieldTypeOption { data_type: Box<FieldType> },
FieldTypeVec { data_type: Box<FieldType> },
FieldTypeStruct { struct_name: syn::Ident },
}
@@ -35,7 +36,17 @@ impl FieldType {
"u64" => Some(FieldType::FieldTypeU64),
"f32" => Some(FieldType::FieldTypeF32),
"f64" => Some(FieldType::FieldTypeF64),
"Vec" => get_vec_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 {
data_type: Box::new(FieldType::from_ident(&p).unwrap()),
}
}),
"Vec" => get_sub_type(t).map(|data_type| {
let p = syn::PathSegment {
ident: data_type,
arguments: syn::PathArguments::None,
@@ -62,7 +73,7 @@ pub fn get_field_type(field: &syn::Field) -> Option<FieldType> {
}
}
fn get_vec_type(t: &syn::PathSegment) -> Option<syn::Ident> {
fn get_sub_type(t: &syn::PathSegment) -> Option<syn::Ident> {
if let syn::PathArguments::AngleBracketed(ref args) = t.arguments {
if let Some(Pair::End(tt)) = args.args.first() {
if let syn::GenericArgument::Type(ref argument) = *tt {

View File

@@ -46,7 +46,7 @@ pub fn serialize(
| Some(FieldType::FieldTypeU64)
| Some(FieldType::FieldTypeF32)
| Some(FieldType::FieldTypeF64) => Some(quote!{
.attr(#label_name, &*{
let struct_start_event = struct_start_event.attr(#label_name, &*{
use std::mem;
unsafe {
let content = format!("{}", self.#label);
@@ -54,11 +54,50 @@ pub fn serialize(
mem::forget(content);
ret
}
})
});
}),
Some(FieldType::FieldTypeOption { data_type }) => {
let dt = Box::into_raw(data_type);
match unsafe { dt.as_ref() } {
Some(&FieldType::FieldTypeString) => Some(quote!{
let struct_start_event =
if let Some(ref value) = self.#label {
struct_start_event.attr(#label_name, &value)
} else {
struct_start_event
};
}),
Some(&FieldType::FieldTypeBool)
| Some(&FieldType::FieldTypeI8)
| Some(&FieldType::FieldTypeU8)
| Some(&FieldType::FieldTypeI16)
| Some(&FieldType::FieldTypeU16)
| Some(&FieldType::FieldTypeI32)
| Some(&FieldType::FieldTypeU32)
| Some(&FieldType::FieldTypeI64)
| Some(&FieldType::FieldTypeU64)
| Some(&FieldType::FieldTypeF32)
| Some(&FieldType::FieldTypeF64) => Some(quote!{
let struct_start_event =
if let Some(value) = self.#label {
struct_start_event.attr(#label_name, &*{
use std::mem;
unsafe {
let content = format!("{}", value);
let ret : &'static str = mem::transmute(&content as &str);
mem::forget(content);
ret
}
})
} else {
struct_start_event
};
}),
_ => None,
}
}
Some(FieldType::FieldTypeStruct { .. }) => Some(quote!{
.attr(#label_name, &*{
let struct_start_event = struct_start_event.attr(#label_name, &*{
use std::mem;
match yaserde::ser::to_string_content(&self.#label) {
Ok(value) => {
@@ -70,7 +109,7 @@ pub fn serialize(
},
Err(msg) => return Err("Unable to serialize content".to_owned()),
}
})
});
}),
_ => None,
}
@@ -156,6 +195,47 @@ pub fn serialize(
let end_event = XmlEvent::end_element();
let _ret = writer.write(end_event);
}),
Some(FieldType::FieldTypeOption { data_type }) => {
let dt = Box::into_raw(data_type);
match unsafe { dt.as_ref() } {
Some(&FieldType::FieldTypeString) => Some(quote!{
if let Some(ref item) = 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);
}
}),
Some(&FieldType::FieldTypeBool)
| Some(&FieldType::FieldTypeI8)
| Some(&FieldType::FieldTypeU8)
| Some(&FieldType::FieldTypeI16)
| Some(&FieldType::FieldTypeU16)
| Some(&FieldType::FieldTypeI32)
| Some(&FieldType::FieldTypeU32)
| Some(&FieldType::FieldTypeI64)
| Some(&FieldType::FieldTypeU64)
| Some(&FieldType::FieldTypeF32)
| Some(&FieldType::FieldTypeF64) => Some(quote!{
if let Some(item) = self.#label {
let start_event = XmlEvent::start_element(#label_name);
let _ret = writer.write(start_event);
let content = format!("{}", item);
let data_event = XmlEvent::characters(&content);
let _ret = writer.write(data_event);
let end_event = XmlEvent::end_element();
let _ret = writer.write(end_event);
}
}),
_ => None,
}
}
Some(FieldType::FieldTypeStruct { .. }) => Some(quote!{
writer.set_skip_start_end(false);
match self.#label.serialize(writer) {
@@ -202,6 +282,19 @@ pub fn serialize(
let _ret = writer.write(end_event);
}
}),
Some(&FieldType::FieldTypeOption { .. }) => Some(quote!{
for item in &self.#label {
if let Some(value) = item {
writer.set_skip_start_end(false);
match value.serialize(writer) {
Ok(()) => {},
Err(msg) => {
return Err(msg);
},
};
}
}
}),
Some(&FieldType::FieldTypeStruct { .. }) => Some(quote!{
for item in &self.#label {
writer.set_skip_start_end(false);
@@ -241,7 +334,8 @@ pub fn serialize(
error!("Struct: start to expand {:?}", #root);
let skip = writer.skip_start_end();
if !skip {
let struct_start_event = XmlEvent::start_element(#root)#build_attributes#add_namespaces;
let struct_start_event = XmlEvent::start_element(#root)#add_namespaces;
#build_attributes
let _ret = writer.write(struct_start_event);
}