Add deserialization for enums with values (#8)
This commit is contained in:
		
							parent
							
								
									a2bf70c5bd
								
							
						
					
					
						commit
						d277d5137b
					
				| @ -351,6 +351,178 @@ fn de_attribute_enum() { | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn de_complex_enum() { | ||||
|   #[derive(YaDeserialize, PartialEq, Debug)] | ||||
|   pub struct XmlStruct { | ||||
|     background: Color, | ||||
|   } | ||||
| 
 | ||||
|   #[derive(YaDeserialize, PartialEq, Debug, Default)] | ||||
|   pub struct OtherStruct { | ||||
|     fi: i32, | ||||
|     se: i32, | ||||
|   } | ||||
| 
 | ||||
|   #[derive(YaDeserialize, PartialEq, Debug)] | ||||
|   pub enum Color { | ||||
|     White, | ||||
|     Black(String), | ||||
|     Orange(std::string::String), | ||||
|     Red(i32), | ||||
|     Green(OtherStruct), | ||||
|     Yellow(Option<String>), | ||||
|     Brown(Option<OtherStruct>), | ||||
|     Blue(Vec<String>), | ||||
|     Purple(Vec<i32>), | ||||
|     Magenta(Vec<OtherStruct>), | ||||
|     #[yaserde(rename = "NotSoCyan")] | ||||
|     Cyan(Vec<OtherStruct>), | ||||
|   } | ||||
| 
 | ||||
|   impl Default for Color { | ||||
|     fn default() -> Color { | ||||
|       Color::White | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   let content = r#"<?xml version="1.0" encoding="utf-8"?>
 | ||||
|     <base> | ||||
|       <background> | ||||
|         <Black>text</Black> | ||||
|       </background> | ||||
|     </base> | ||||
|   "#;
 | ||||
|   convert_and_validate!( | ||||
|     content, | ||||
|     XmlStruct, | ||||
|     XmlStruct { | ||||
|       background: Color::Black(String::from("text")), | ||||
|     } | ||||
|   ); | ||||
| 
 | ||||
|   let content = r#"<?xml version="1.0" encoding="utf-8"?>
 | ||||
|     <base> | ||||
|       <background> | ||||
|         <Orange>text</Orange> | ||||
|       </background> | ||||
|     </base> | ||||
|   "#;
 | ||||
|   convert_and_validate!( | ||||
|     content, | ||||
|     XmlStruct, | ||||
|     XmlStruct { | ||||
|       background: Color::Orange(String::from("text")), | ||||
|     } | ||||
|   ); | ||||
| 
 | ||||
|   let content = r#"<?xml version="1.0" encoding="utf-8"?>
 | ||||
|     <base> | ||||
|       <background> | ||||
|         <Green> | ||||
|           <fi>12</fi> | ||||
|           <se>23</se> | ||||
|         </Green> | ||||
|       </background> | ||||
|     </base> | ||||
|   "#;
 | ||||
|   convert_and_validate!( | ||||
|     content, | ||||
|     XmlStruct, | ||||
|     XmlStruct { | ||||
|       background: Color::Green(OtherStruct { fi: 12, se: 23 }), | ||||
|     } | ||||
|   ); | ||||
| 
 | ||||
|   let content = r#"<?xml version="1.0" encoding="utf-8"?>
 | ||||
|     <base> | ||||
|       <background> | ||||
|         <Brown> | ||||
|           <fi>12</fi> | ||||
|           <se>23</se> | ||||
|         </Brown> | ||||
|       </background> | ||||
|     </base> | ||||
|   "#;
 | ||||
|   convert_and_validate!( | ||||
|     content, | ||||
|     XmlStruct, | ||||
|     XmlStruct { | ||||
|       background: Color::Brown(Some(OtherStruct { fi: 12, se: 23 })), | ||||
|     } | ||||
|   ); | ||||
| 
 | ||||
|   let content = r#"<?xml version="1.0" encoding="utf-8"?>
 | ||||
|     <base> | ||||
|       <background> | ||||
|         <Blue>abc</Blue> | ||||
|         <Blue>def</Blue> | ||||
|       </background> | ||||
|     </base> | ||||
|   "#;
 | ||||
|   convert_and_validate!( | ||||
|     content, | ||||
|     XmlStruct, | ||||
|     XmlStruct { | ||||
|       background: Color::Blue(vec![String::from("abc"), String::from("def")]), | ||||
|     } | ||||
|   ); | ||||
| 
 | ||||
|   let content = r#"<?xml version="1.0" encoding="utf-8"?>
 | ||||
|     <base> | ||||
|       <background> | ||||
|         <Purple>12</Purple> | ||||
|         <Purple>43</Purple> | ||||
|       </background> | ||||
|     </base> | ||||
|   "#;
 | ||||
|   convert_and_validate!( | ||||
|     content, | ||||
|     XmlStruct, | ||||
|     XmlStruct { | ||||
|       background: Color::Purple(vec![12, 43]), | ||||
|     } | ||||
|   ); | ||||
| 
 | ||||
|   let content = r#"<?xml version="1.0" encoding="utf-8"?>
 | ||||
|     <base> | ||||
|       <background> | ||||
|         <Magenta><fi>12</fi><se>23</se></Magenta> | ||||
|         <Magenta><fi>63</fi><se>98</se></Magenta> | ||||
|       </background> | ||||
|     </base> | ||||
|   "#;
 | ||||
|   convert_and_validate!( | ||||
|     content, | ||||
|     XmlStruct, | ||||
|     XmlStruct { | ||||
|       background: Color::Magenta(vec![ | ||||
|         OtherStruct { fi: 12, se: 23 }, | ||||
|         OtherStruct { fi: 63, se: 98 } | ||||
|       ]), | ||||
|     } | ||||
|   ); | ||||
| 
 | ||||
|   let content = r#"<?xml version="1.0" encoding="utf-8"?>
 | ||||
|     <base xmlns:ns="http://www.sample.com/ns/domain"> | ||||
|       <background> | ||||
|         <NotSoCyan><fi>12</fi><se>23</se></NotSoCyan> | ||||
|         <NotSoCyan><fi>63</fi><se>98</se></NotSoCyan> | ||||
|       </background> | ||||
|     </base> | ||||
|   "#;
 | ||||
|   convert_and_validate!( | ||||
|     content, | ||||
|     XmlStruct, | ||||
|     XmlStruct { | ||||
|       background: Color::Cyan(vec![ | ||||
|         OtherStruct { fi: 12, se: 23 }, | ||||
|         OtherStruct { fi: 63, se: 98 } | ||||
|       ]) | ||||
|     } | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn de_name_issue_21() { | ||||
|   #[derive(YaDeserialize, PartialEq, Debug)] | ||||
|  | ||||
| @ -1,8 +1,6 @@ | ||||
| use attribute::*; | ||||
| use de::build_default_value::build_default_value; | ||||
| use field_type::*; | ||||
| use proc_macro2::{Span, TokenStream}; | ||||
| use quote::TokenStreamExt; | ||||
| use std::collections::BTreeMap; | ||||
| use syn::DataEnum; | ||||
| use syn::Fields; | ||||
| @ -14,250 +12,18 @@ pub fn parse( | ||||
|   root: &str, | ||||
|   _namespaces: &BTreeMap<String, String>, | ||||
| ) -> TokenStream { | ||||
|   let variables: TokenStream = data_enum | ||||
|     .variants | ||||
|     .iter() | ||||
|     .map(|variant| match variant.fields { | ||||
|       Fields::Unit => None, | ||||
|       Fields::Named(ref fields) => { | ||||
|         let enum_fields = fields | ||||
|           .named | ||||
|           .iter() | ||||
|           .map(|field| { | ||||
|             let field_label = &field.ident; | ||||
|             let field_attrs = YaSerdeAttribute::parse(&field.attrs); | ||||
| 
 | ||||
|             match get_field_type(field) { | ||||
|               Some(FieldType::FieldTypeString) => build_default_value( | ||||
|                 field_label, | ||||
|                 "e! {String}, | ||||
|                 "e! {"".to_string()}, | ||||
|                 &field_attrs.default, | ||||
|               ), | ||||
|               Some(FieldType::FieldTypeBool) => build_default_value( | ||||
|                 field_label, | ||||
|                 "e! {bool}, | ||||
|                 "e! {false}, | ||||
|                 &field_attrs.default, | ||||
|               ), | ||||
|               Some(FieldType::FieldTypeI8) => { | ||||
|                 build_default_value(field_label, "e! {i8}, "e! {0}, &field_attrs.default) | ||||
|               } | ||||
|               Some(FieldType::FieldTypeU8) => { | ||||
|                 build_default_value(field_label, "e! {u8}, "e! {0}, &field_attrs.default) | ||||
|               } | ||||
|               Some(FieldType::FieldTypeI16) => build_default_value( | ||||
|                 field_label, | ||||
|                 "e! {i16}, | ||||
|                 "e! {0}, | ||||
|                 &field_attrs.default, | ||||
|               ), | ||||
|               Some(FieldType::FieldTypeU16) => build_default_value( | ||||
|                 field_label, | ||||
|                 "e! {u16}, | ||||
|                 "e! {0}, | ||||
|                 &field_attrs.default, | ||||
|               ), | ||||
|               Some(FieldType::FieldTypeI32) => build_default_value( | ||||
|                 field_label, | ||||
|                 "e! {i32}, | ||||
|                 "e! {0}, | ||||
|                 &field_attrs.default, | ||||
|               ), | ||||
|               Some(FieldType::FieldTypeU32) => build_default_value( | ||||
|                 field_label, | ||||
|                 "e! {u32}, | ||||
|                 "e! {0}, | ||||
|                 &field_attrs.default, | ||||
|               ), | ||||
|               Some(FieldType::FieldTypeI64) => build_default_value( | ||||
|                 field_label, | ||||
|                 "e! {i64}, | ||||
|                 "e! {0}, | ||||
|                 &field_attrs.default, | ||||
|               ), | ||||
|               Some(FieldType::FieldTypeU64) => build_default_value( | ||||
|                 field_label, | ||||
|                 "e! {u64}, | ||||
|                 "e! {0}, | ||||
|                 &field_attrs.default, | ||||
|               ), | ||||
|               Some(FieldType::FieldTypeF32) => build_default_value( | ||||
|                 field_label, | ||||
|                 "e! {f32}, | ||||
|                 "e! {0}, | ||||
|                 &field_attrs.default, | ||||
|               ), | ||||
|               Some(FieldType::FieldTypeF64) => build_default_value( | ||||
|                 field_label, | ||||
|                 "e! {f64}, | ||||
|                 "e! {0}, | ||||
|                 &field_attrs.default, | ||||
|               ), | ||||
|               Some(FieldType::FieldTypeStruct { struct_name }) => build_default_value( | ||||
|                 field_label, | ||||
|                 "e! {#struct_name}, | ||||
|                 "e! {#struct_name::default()}, | ||||
|                 &field_attrs.default, | ||||
|               ), | ||||
|               Some(FieldType::FieldTypeOption { .. }) => { | ||||
|                 if let Some(d) = &field_attrs.default { | ||||
|                   let default_function = Ident::new(&d, Span::call_site()); | ||||
| 
 | ||||
|                   Some(quote! { | ||||
|                     #[allow(unused_mut, non_snake_case, non_camel_case_types)] | ||||
|                     let mut #field_label = #default_function(); | ||||
|                   }) | ||||
|                 } else { | ||||
|                   Some(quote! { | ||||
|                     #[allow(unused_mut, non_snake_case, non_camel_case_types)] | ||||
|                     let mut #field_label = None; | ||||
|                   }) | ||||
|                 } | ||||
|               } | ||||
|               Some(FieldType::FieldTypeVec { data_type }) => { | ||||
|                 let dt = Box::into_raw(data_type); | ||||
|                 match unsafe { dt.as_ref() } { | ||||
|                   Some(&FieldType::FieldTypeString) => build_default_value( | ||||
|                     field_label, | ||||
|                     "e! {Vec<String>}, | ||||
|                     "e! {vec![]}, | ||||
|                     &field_attrs.default, | ||||
|                   ), | ||||
|                   Some(&FieldType::FieldTypeBool) => build_default_value( | ||||
|                     field_label, | ||||
|                     "e! {Vec<bool>}, | ||||
|                     "e! {vec![]}, | ||||
|                     &field_attrs.default, | ||||
|                   ), | ||||
|                   Some(&FieldType::FieldTypeI8) => build_default_value( | ||||
|                     field_label, | ||||
|                     "e! {Vec<i8>}, | ||||
|                     "e! {vec![]}, | ||||
|                     &field_attrs.default, | ||||
|                   ), | ||||
|                   Some(&FieldType::FieldTypeU8) => build_default_value( | ||||
|                     field_label, | ||||
|                     "e! {Vec<u8>}, | ||||
|                     "e! {vec![]}, | ||||
|                     &field_attrs.default, | ||||
|                   ), | ||||
|                   Some(&FieldType::FieldTypeI16) => build_default_value( | ||||
|                     field_label, | ||||
|                     "e! {Vec<i16>}, | ||||
|                     "e! {vec![]}, | ||||
|                     &field_attrs.default, | ||||
|                   ), | ||||
|                   Some(&FieldType::FieldTypeU16) => build_default_value( | ||||
|                     field_label, | ||||
|                     "e! {Vec<u16>}, | ||||
|                     "e! {vec![]}, | ||||
|                     &field_attrs.default, | ||||
|                   ), | ||||
|                   Some(&FieldType::FieldTypeI32) => build_default_value( | ||||
|                     field_label, | ||||
|                     "e! {Vec<i32>}, | ||||
|                     "e! {vec![]}, | ||||
|                     &field_attrs.default, | ||||
|                   ), | ||||
|                   Some(&FieldType::FieldTypeU32) => build_default_value( | ||||
|                     field_label, | ||||
|                     "e! {Vec<u32>}, | ||||
|                     "e! {vec![]}, | ||||
|                     &field_attrs.default, | ||||
|                   ), | ||||
|                   Some(&FieldType::FieldTypeI64) => build_default_value( | ||||
|                     field_label, | ||||
|                     "e! {Vec<i64>}, | ||||
|                     "e! {vec![]}, | ||||
|                     &field_attrs.default, | ||||
|                   ), | ||||
|                   Some(&FieldType::FieldTypeU64) => build_default_value( | ||||
|                     field_label, | ||||
|                     "e! {Vec<u64>}, | ||||
|                     "e! {vec![]}, | ||||
|                     &field_attrs.default, | ||||
|                   ), | ||||
|                   Some(&FieldType::FieldTypeF32) => build_default_value( | ||||
|                     field_label, | ||||
|                     "e! {Vec<f32>}, | ||||
|                     "e! {vec![]}, | ||||
|                     &field_attrs.default, | ||||
|                   ), | ||||
|                   Some(&FieldType::FieldTypeF64) => build_default_value( | ||||
|                     field_label, | ||||
|                     "e! {Vec<f64>}, | ||||
|                     "e! {vec![]}, | ||||
|                     &field_attrs.default, | ||||
|                   ), | ||||
|                   Some(&FieldType::FieldTypeStruct { ref struct_name }) => build_default_value( | ||||
|                     field_label, | ||||
|                     "e! {Vec<#struct_name>}, | ||||
|                     "e! {vec![]}, | ||||
|                     &field_attrs.default, | ||||
|                   ), | ||||
|                   Some(&FieldType::FieldTypeOption { .. }) | ||||
|                   | Some(&FieldType::FieldTypeVec { .. }) => { | ||||
|                     unimplemented!(); | ||||
|                   } | ||||
|                   None => { | ||||
|                     unimplemented!(); | ||||
|                   } | ||||
|                 } | ||||
|               } | ||||
|               None => None, | ||||
|             } | ||||
|           }) | ||||
|           .filter(|x| x.is_some()) | ||||
|           .map(|x| x.unwrap()) | ||||
|           .fold(TokenStream::new(), |mut sum, val| { | ||||
|             sum.append_all(val); | ||||
|             sum | ||||
|           }); | ||||
| 
 | ||||
|         Some(enum_fields) | ||||
|       } | ||||
|       Fields::Unnamed(ref _fields) => { | ||||
|         unimplemented!(); | ||||
|       } | ||||
|     }) | ||||
|     .filter(|x| x.is_some()) | ||||
|     .map(|x| x.unwrap()) | ||||
|     .fold(TokenStream::new(), |mut sum, val| { | ||||
|       sum.append_all(val); | ||||
|       sum | ||||
|     }); | ||||
| 
 | ||||
|   let match_to_enum: TokenStream = data_enum | ||||
|     .variants | ||||
|     .iter() | ||||
|     .map(|variant| { | ||||
|       let field_attrs = YaSerdeAttribute::parse(&variant.attrs); | ||||
|       let renamed_label = match field_attrs.rename { | ||||
|         Some(value) => Ident::new(&value.to_string(), Span::call_site()), | ||||
|         None => variant.ident.clone(), | ||||
|       }; | ||||
|       let label = &variant.ident; | ||||
|       let label_name = renamed_label.to_string(); | ||||
| 
 | ||||
|       match variant.fields { | ||||
|         Fields::Unit => Some(quote! { | ||||
|           #label_name => { | ||||
|             simple_enum_value = Some(#name::#label); | ||||
|           } | ||||
|         }), | ||||
|         _ => None, | ||||
|       } | ||||
|     }) | ||||
|     .filter(|x| x.is_some()) | ||||
|     .map(|x| x.unwrap()) | ||||
|     .fold(TokenStream::new(), |mut tokens, token| { | ||||
|       tokens.append_all(token); | ||||
|       tokens | ||||
|     }); | ||||
|     .map(|variant| parse_variant(variant, name)) | ||||
|     .filter_map(|f| f) | ||||
|     .collect(); | ||||
| 
 | ||||
|   quote! { | ||||
|     use xml::reader::XmlEvent; | ||||
|     use yaserde::Visitor; | ||||
|     #[allow(unknown_lints, unused_imports)] | ||||
|     use std::str::FromStr; | ||||
| 
 | ||||
|     impl YaDeserialize for #name { | ||||
|       #[allow(unused_variables)] | ||||
| @ -271,16 +37,18 @@ pub fn parse( | ||||
|         debug!("Enum: start to parse {:?}", named_element); | ||||
| 
 | ||||
|         #[allow(unused_assignments, unused_mut)] | ||||
|         let mut simple_enum_value = None; | ||||
| 
 | ||||
|         #variables | ||||
|         let mut enum_value = None; | ||||
| 
 | ||||
|         loop { | ||||
|           match reader.peek()?.to_owned() { | ||||
|             XmlEvent::StartElement{name, attributes, namespace: _namespace} => { | ||||
|               debug!("Enum: {}: {}", named_element, name.local_name.as_str()); | ||||
|               if name.local_name == named_element { | ||||
|                 let _next = reader.next_event(); | ||||
|             XmlEvent::StartElement{ref name, ref attributes, ..} => { | ||||
| 
 | ||||
|               match name.local_name.as_str() { | ||||
|                 #match_to_enum | ||||
|                 named_element => { | ||||
|                   let _root = reader.next_event(); | ||||
|                 } | ||||
|               } | ||||
| 
 | ||||
|               if let XmlEvent::Characters(content) = reader.peek()?.to_owned() { | ||||
|                 match content.as_str() { | ||||
| @ -289,23 +57,22 @@ pub fn parse( | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|             }, | ||||
|             XmlEvent::EndElement{name} => { | ||||
|               if name.local_name.as_str() == named_element { | ||||
|             XmlEvent::EndElement{ref name} => { | ||||
|               if name.local_name == named_element { | ||||
|                 break; | ||||
|               } | ||||
|               let _root = reader.next_event(); | ||||
|             }, | ||||
|             xml::reader::XmlEvent::Characters(characters_content) => { | ||||
|             } | ||||
|             XmlEvent::Characters(ref text_content) => { | ||||
|               let _root = reader.next_event(); | ||||
|             }, | ||||
|             } | ||||
|             event => { | ||||
|               return Err(format!("unknown event {:?}", event)) | ||||
|             }, | ||||
|             } | ||||
|           } | ||||
|         } | ||||
| 
 | ||||
|         match simple_enum_value { | ||||
|         match enum_value { | ||||
|           Some(value) => Ok(value), | ||||
|           None => { | ||||
|             Ok(#name::default()) | ||||
| @ -315,3 +82,227 @@ pub fn parse( | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| fn parse_variant(variant: &syn::Variant, name: &Ident) -> Option<TokenStream> { | ||||
|   let xml_element_name = YaSerdeAttribute::parse(&variant.attrs) | ||||
|     .rename | ||||
|     .unwrap_or(variant.ident.to_string()); | ||||
| 
 | ||||
|   let variant_name = { | ||||
|     let label = &variant.ident; | ||||
|     quote! { #name::#label } | ||||
|   }; | ||||
| 
 | ||||
|   match variant.fields { | ||||
|     Fields::Unit => Some(quote! { | ||||
|       #xml_element_name => { | ||||
|         enum_value = Some(#variant_name); | ||||
|       } | ||||
|     }), | ||||
|     Fields::Unnamed(ref fields) => { | ||||
|       let field_visitors = build_unnamed_field_visitors(fields); | ||||
|       let call_visitors = build_unnamed_visitor_calls(fields, &variant_name); | ||||
| 
 | ||||
|       if fields.unnamed.len() > 1 { | ||||
|         unimplemented!("enum variant with multiple fields") | ||||
|       } | ||||
| 
 | ||||
|       Some( | ||||
|         fields | ||||
|           .unnamed | ||||
|           .iter() | ||||
|           .take(1) | ||||
|           .map(|_field| { | ||||
|             quote! { | ||||
|               #xml_element_name => { | ||||
|                 #field_visitors | ||||
|                 #call_visitors | ||||
|               } | ||||
|             } | ||||
|           }) | ||||
|           .collect(), | ||||
|       ) | ||||
|     } | ||||
|     _ => None, | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| fn build_unnamed_field_visitors(fields: &syn::FieldsUnnamed) -> TokenStream { | ||||
|   fields | ||||
|     .unnamed | ||||
|     .iter() | ||||
|     .enumerate() | ||||
|     .map(|(idx, field)| { | ||||
|       let visitor_label = Ident::new(&format!("__Visitor_{}", idx), Span::call_site()); | ||||
| 
 | ||||
|       let make_visitor = | ||||
|         |visitor: &TokenStream, field_type: &TokenStream, fn_body: &TokenStream| { | ||||
|           Some(quote! { | ||||
|             #[allow(non_snake_case, non_camel_case_types)] | ||||
|             struct #visitor_label; | ||||
|             impl<'de> Visitor<'de> for #visitor_label { | ||||
|               type Value = #field_type; | ||||
| 
 | ||||
|               fn #visitor(self, v: &str) -> Result<Self::Value, String> { | ||||
|                 #fn_body | ||||
|               } | ||||
|             } | ||||
|           }) | ||||
|         }; | ||||
| 
 | ||||
|       let simple_type_visitor = |simple_type| { | ||||
|         let (field_type, visitor) = convert_simple_type(simple_type); | ||||
| 
 | ||||
|         make_visitor( | ||||
|           &visitor, | ||||
|           &field_type, | ||||
|           "e! { Ok(#field_type::from_str(v).unwrap()) }, | ||||
|         ) | ||||
|       }; | ||||
| 
 | ||||
|       get_field_type(field).and_then(|f| match f { | ||||
|         FieldType::FieldTypeStruct { struct_name } => { | ||||
|           let struct_id: String = struct_name | ||||
|             .segments | ||||
|             .iter() | ||||
|             .map(|s| s.ident.to_string()) | ||||
|             .collect(); | ||||
| 
 | ||||
|           make_visitor( | ||||
|             "e! { visit_str }, | ||||
|             "e! { #struct_name }, | ||||
|             "e! { | ||||
|               let content = "<".to_string() + #struct_id + ">" + v + "</" + #struct_id + ">"; | ||||
|               let value : Result<#struct_name, String> = yaserde::de::from_str(&content); | ||||
|               value | ||||
|             }, | ||||
|           ) | ||||
|         } | ||||
|         FieldType::FieldTypeOption { data_type } | FieldType::FieldTypeVec { data_type } => { | ||||
|           match *data_type { | ||||
|             FieldType::FieldTypeStruct { .. } => None, | ||||
|             simple_type => simple_type_visitor(simple_type), | ||||
|           } | ||||
|         } | ||||
|         simple_type => simple_type_visitor(simple_type), | ||||
|       }) | ||||
|     }) | ||||
|     .filter_map(|f| f) | ||||
|     .collect() | ||||
| } | ||||
| 
 | ||||
| fn build_unnamed_visitor_calls( | ||||
|   fields: &syn::FieldsUnnamed, | ||||
|   variant_name: &TokenStream, | ||||
| ) -> TokenStream { | ||||
|   fields | ||||
|     .unnamed | ||||
|     .iter() | ||||
|     .enumerate() | ||||
|     .map(|(idx, field)| { | ||||
|       let visitor_label = Ident::new(&format!("__Visitor_{}", idx), Span::call_site()); | ||||
| 
 | ||||
|       let call_simple_type_visitor = |simple_type, action| { | ||||
|         let (field_type, visitor) = convert_simple_type(simple_type); | ||||
| 
 | ||||
|         let label_name = format!("field_{}", idx); | ||||
| 
 | ||||
|         Some(quote! { | ||||
|           let visitor = #visitor_label{}; | ||||
| 
 | ||||
|           if let XmlEvent::StartElement {name, ..} = reader.peek()?.clone() { | ||||
|             if let Some(namespace) = name.namespace { | ||||
|               match namespace.as_str() { | ||||
|                 bad_ns => { | ||||
|                   let msg = format!("bad field namespace for {}, found {}", | ||||
|                     name.local_name.as_str(), | ||||
|                     bad_ns); | ||||
|                   return Err(msg); | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
|             reader.set_map_value() | ||||
|           } | ||||
| 
 | ||||
|           let result = reader.read_inner_value::<#field_type, _>(|reader| { | ||||
|             if let XmlEvent::EndElement { .. } = *reader.peek()? { | ||||
|               return visitor.#visitor(""); | ||||
|             } | ||||
| 
 | ||||
|             if let Ok(XmlEvent::Characters(s)) = reader.next_event() { | ||||
|               visitor.#visitor(&s) | ||||
|             } else { | ||||
|               Err(format!("unable to parse content for {}", #label_name)) | ||||
|             } | ||||
|           }); | ||||
| 
 | ||||
|           if let Ok(value) = result { | ||||
|             #action | ||||
|           } | ||||
|         }) | ||||
|       }; | ||||
| 
 | ||||
|       let call_struct_visitor = |struct_name, action| { | ||||
|         Some(quote! { | ||||
|           reader.set_map_value(); | ||||
|           match #struct_name::deserialize(reader) { | ||||
|             Ok(value) => { | ||||
|               #action; | ||||
|               let _root = reader.next_event(); | ||||
|             }, | ||||
|             Err(msg) => { | ||||
|               return Err(msg); | ||||
|             }, | ||||
|           } | ||||
|         }) | ||||
|       }; | ||||
| 
 | ||||
|       let set_val = quote! { enum_value = Some(#variant_name(value)) }; | ||||
|       let set_opt = quote! { enum_value = Some(#variant_name(Some(value))) }; | ||||
|       let set_vec = quote! { | ||||
|         match enum_value { | ||||
|           Some(ref mut v) => match v { | ||||
|             #variant_name(ref mut v) => v.push(value), | ||||
|             _ => return Err(String::from("Got sequence of different types")) | ||||
|           } | ||||
|           None => { | ||||
|             enum_value = Some(#variant_name(vec![value])); | ||||
|           } | ||||
|         } | ||||
|       }; | ||||
| 
 | ||||
|       get_field_type(field).and_then(|f| match f { | ||||
|         FieldType::FieldTypeStruct { struct_name } => call_struct_visitor(struct_name, set_val), | ||||
|         FieldType::FieldTypeOption { data_type } => match *data_type { | ||||
|           FieldType::FieldTypeStruct { struct_name } => call_struct_visitor(struct_name, set_opt), | ||||
|           simple_type => call_simple_type_visitor(simple_type, set_opt), | ||||
|         }, | ||||
|         FieldType::FieldTypeVec { data_type } => match *data_type { | ||||
|           FieldType::FieldTypeStruct { struct_name } => call_struct_visitor(struct_name, set_vec), | ||||
|           simple_type => call_simple_type_visitor(simple_type, set_vec), | ||||
|         }, | ||||
| 
 | ||||
|         simple_type => call_simple_type_visitor(simple_type, set_val), | ||||
|       }) | ||||
|     }) | ||||
|     .filter_map(|f| f) | ||||
|     .collect() | ||||
| } | ||||
| 
 | ||||
| fn convert_simple_type(simple_type: FieldType) -> (TokenStream, TokenStream) { | ||||
|   match simple_type { | ||||
|     FieldType::FieldTypeString => (quote! {String}, quote! {visit_str}), | ||||
|     FieldType::FieldTypeBool => (quote! {bool}, quote! {visit_bool}), | ||||
|     FieldType::FieldTypeU8 => (quote! {u8}, quote! {visit_u8}), | ||||
|     FieldType::FieldTypeI8 => (quote! {i8}, quote! {visit_i8}), | ||||
|     FieldType::FieldTypeU16 => (quote! {u16}, quote! {visit_u16}), | ||||
|     FieldType::FieldTypeI16 => (quote! {i16}, quote! {visit_i16}), | ||||
|     FieldType::FieldTypeU32 => (quote! {u32}, quote! {visit_u32}), | ||||
|     FieldType::FieldTypeI32 => (quote! {i32}, quote! {visit_i32}), | ||||
|     FieldType::FieldTypeU64 => (quote! {u64}, quote! {visit_u64}), | ||||
|     FieldType::FieldTypeI64 => (quote! {i64}, quote! {visit_i64}), | ||||
|     FieldType::FieldTypeF32 => (quote! {f32}, quote! {visit_f32}), | ||||
|     FieldType::FieldTypeF64 => (quote! {f64}, quote! {visit_f64}), | ||||
|     _ => panic!("Not a simple type: {:?}", simple_type), | ||||
|   } | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user