diff --git a/yaserde/tests/deserializer.rs b/yaserde/tests/deserializer.rs index 2b94548..a30607e 100644 --- a/yaserde/tests/deserializer.rs +++ b/yaserde/tests/deserializer.rs @@ -48,6 +48,52 @@ fn de_basic() { ); } +#[test] +fn de_multiple_segments() { + mod other_mod { + use std::io::Read; + use yaserde::YaDeserialize; + + #[derive(YaDeserialize, PartialEq, Debug, Default)] + pub struct Page { + pub number: i32, + pub text: std::string::String, + } + } + + #[derive(YaDeserialize, PartialEq, Debug)] + #[yaserde(root = "book")] + pub struct Book { + author: std::string::String, + title: std::string::String, + page: other_mod::Page, + } + + let content = r#" + + Antoine de Saint-Exupéry + Little prince + + 40 + The Earth is not just an ordinary planet! + + + "#; + + convert_and_validate!( + content, + Book, + Book { + author: String::from("Antoine de Saint-Exupéry"), + title: String::from("Little prince"), + page: other_mod::Page { + number: 40, + text: String::from("The Earth is not just an ordinary planet!"), + }, + } + ); +} + #[test] fn de_list_of_items() { #[derive(YaDeserialize, PartialEq, Debug)] diff --git a/yaserde_derive/src/de/expand_struct.rs b/yaserde_derive/src/de/expand_struct.rs index 22debe1..0864af9 100644 --- a/yaserde_derive/src/de/expand_struct.rs +++ b/yaserde_derive/src/de/expand_struct.rs @@ -2,7 +2,7 @@ use attribute::*; use de::build_default_value::build_default_value; use field_type::*; use proc_macro2::{Span, TokenStream}; -use quote::TokenStreamExt; +use quote::{ToTokens, TokenStreamExt}; use std::collections::BTreeMap; use syn::DataStruct; use syn::Ident; @@ -249,9 +249,13 @@ pub fn parse( build_declare_visitor("e! {f64}, "e! {visit_f64}, &visitor_label) } Some(FieldType::FieldTypeStruct { struct_name }) => { - let struct_id = struct_name.to_string(); + let struct_id: String = struct_name + .segments + .iter() + .map(|s| s.ident.to_string()) + .collect(); let struct_ident = Ident::new( - &format!("__Visitor_{}_{}", label_name, struct_name), + &format!("__Visitor_{}_{}", label_name, struct_id), Span::call_site(), ); @@ -309,7 +313,10 @@ pub fn parse( build_declare_visitor("e! {f64}, "e! {visit_f64}, &visitor_label) } Some(&FieldType::FieldTypeStruct { ref struct_name }) => { - let struct_ident = Ident::new(&format!("{}", struct_name), Span::call_site()); + let struct_ident = Ident::new( + &format!("{}", struct_name.into_token_stream()), + Span::call_site(), + ); Some(quote! { #[allow(non_snake_case, non_camel_case_types)] struct #visitor_label; @@ -363,7 +370,10 @@ pub fn parse( build_declare_visitor("e! {f64}, "e! {visit_f64}, &visitor_label) } Some(&FieldType::FieldTypeStruct { ref struct_name }) => { - let struct_ident = Ident::new(&format!("{}", struct_name), Span::call_site()); + let struct_ident = Ident::new( + &format!("{}", struct_name.into_token_stream()), + Span::call_site(), + ); Some(quote! { #[allow(non_snake_case, non_camel_case_types)] struct #visitor_label; @@ -685,7 +695,10 @@ pub fn parse( ) } Some(&FieldType::FieldTypeStruct { ref struct_name }) => { - let struct_ident = Ident::new(&format!("{}", struct_name), Span::call_site()); + let struct_ident = Ident::new( + &format!("{}", struct_name.into_token_stream()), + Span::call_site(), + ); Some(quote! { #label_name => { reader.set_map_value(); @@ -840,7 +853,10 @@ pub fn parse( ) } Some(&FieldType::FieldTypeStruct { ref struct_name }) => { - let struct_ident = Ident::new(&format!("{}", struct_name), Span::call_site()); + let struct_ident = Ident::new( + &format!("{}", struct_name.into_token_stream()), + Span::call_site(), + ); Some(quote! { #label_name => { reader.set_map_value(); @@ -1064,7 +1080,11 @@ pub fn parse( } Some(FieldType::FieldTypeStruct { struct_name }) => { let struct_ident = Ident::new( - &format!("__Visitor_{}_{}", label_name, struct_name), + &format!( + "__Visitor_{}_{}", + label_name, + struct_name.into_token_stream() + ), Span::call_site(), ); diff --git a/yaserde_derive/src/field_type.rs b/yaserde_derive/src/field_type.rs index f567a98..8975f98 100644 --- a/yaserde_derive/src/field_type.rs +++ b/yaserde_derive/src/field_type.rs @@ -17,48 +17,43 @@ pub enum FieldType { FieldTypeF64, FieldTypeOption { data_type: Box }, FieldTypeVec { data_type: Box }, - FieldTypeStruct { struct_name: syn::Ident }, + FieldTypeStruct { struct_name: syn::Path }, } impl FieldType { - fn from_ident(t: &syn::PathSegment) -> Option { - match t.ident.to_string().as_str() { - "String" => Some(FieldType::FieldTypeString), - "bool" => Some(FieldType::FieldTypeBool), - "i8" => Some(FieldType::FieldTypeI8), - "u8" => Some(FieldType::FieldTypeU8), - "i16" => Some(FieldType::FieldTypeI16), - "u16" => Some(FieldType::FieldTypeU16), - "i32" => Some(FieldType::FieldTypeI32), - "u32" => Some(FieldType::FieldTypeU32), - "i64" => Some(FieldType::FieldTypeI64), - "u64" => Some(FieldType::FieldTypeU64), - "f32" => Some(FieldType::FieldTypeF32), - "f64" => Some(FieldType::FieldTypeF64), - "Option" => get_sub_type(t).map(|data_type| FieldType::FieldTypeOption { - data_type: Box::new(FieldType::from_ident(&data_type).unwrap()), - }), - "Vec" => get_sub_type(t).map(|data_type| FieldType::FieldTypeVec { - data_type: Box::new(FieldType::from_ident(&data_type).unwrap()), - }), - _struct_name => Some(FieldType::FieldTypeStruct { - struct_name: t.ident.clone(), - }), + fn from_ident(path: &syn::Path) -> Option { + match path.segments.last() { + Some(t) => match t.ident.to_string().as_str() { + "String" => Some(FieldType::FieldTypeString), + "bool" => Some(FieldType::FieldTypeBool), + "i8" => Some(FieldType::FieldTypeI8), + "u8" => Some(FieldType::FieldTypeU8), + "i16" => Some(FieldType::FieldTypeI16), + "u16" => Some(FieldType::FieldTypeU16), + "i32" => Some(FieldType::FieldTypeI32), + "u32" => Some(FieldType::FieldTypeU32), + "i64" => Some(FieldType::FieldTypeI64), + "u64" => Some(FieldType::FieldTypeU64), + "f32" => Some(FieldType::FieldTypeF32), + "f64" => Some(FieldType::FieldTypeF64), + "Option" => get_sub_type(t).map(|data_type| FieldType::FieldTypeOption { + data_type: Box::new(FieldType::from_ident(&syn::Path::from(data_type)).unwrap()), + }), + "Vec" => get_sub_type(t).map(|data_type| FieldType::FieldTypeVec { + data_type: Box::new(FieldType::from_ident(&syn::Path::from(data_type)).unwrap()), + }), + _ => Some(FieldType::FieldTypeStruct { + struct_name: path.clone(), + }), + }, + _ => None, } } } pub fn get_field_type(field: &syn::Field) -> Option { match field.ty { - Path(ref path) => { - if path.path.segments.len() != 1 { - return None; - } - match path.path.segments.first() { - Some(path_segment) => FieldType::from_ident(path_segment), - _ => None, - } - } + Path(ref path) => FieldType::from_ident(&path.path), _ => None, } }