Merge pull request #26 from DmitrySamoylov/feature-multisegment-types
Add support for field types with multiple PathSegment's
This commit is contained in:
commit
f0036849f3
@ -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#"
|
||||||
|
<book>
|
||||||
|
<author>Antoine de Saint-Exupéry</author>
|
||||||
|
<title>Little prince</title>
|
||||||
|
<page>
|
||||||
|
<number>40</number>
|
||||||
|
<text>The Earth is not just an ordinary planet!</text>
|
||||||
|
</page>
|
||||||
|
</book>
|
||||||
|
"#;
|
||||||
|
|
||||||
|
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]
|
#[test]
|
||||||
fn de_list_of_items() {
|
fn de_list_of_items() {
|
||||||
#[derive(YaDeserialize, PartialEq, Debug)]
|
#[derive(YaDeserialize, PartialEq, Debug)]
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use attribute::*;
|
|||||||
use de::build_default_value::build_default_value;
|
use de::build_default_value::build_default_value;
|
||||||
use field_type::*;
|
use field_type::*;
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::TokenStreamExt;
|
use quote::{ToTokens, TokenStreamExt};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use syn::DataStruct;
|
use syn::DataStruct;
|
||||||
use syn::Ident;
|
use syn::Ident;
|
||||||
@ -249,9 +249,13 @@ pub fn parse(
|
|||||||
build_declare_visitor("e! {f64}, "e! {visit_f64}, &visitor_label)
|
build_declare_visitor("e! {f64}, "e! {visit_f64}, &visitor_label)
|
||||||
}
|
}
|
||||||
Some(FieldType::FieldTypeStruct { struct_name }) => {
|
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(
|
let struct_ident = Ident::new(
|
||||||
&format!("__Visitor_{}_{}", label_name, struct_name),
|
&format!("__Visitor_{}_{}", label_name, struct_id),
|
||||||
Span::call_site(),
|
Span::call_site(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -309,7 +313,10 @@ pub fn parse(
|
|||||||
build_declare_visitor("e! {f64}, "e! {visit_f64}, &visitor_label)
|
build_declare_visitor("e! {f64}, "e! {visit_f64}, &visitor_label)
|
||||||
}
|
}
|
||||||
Some(&FieldType::FieldTypeStruct { ref struct_name }) => {
|
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! {
|
Some(quote! {
|
||||||
#[allow(non_snake_case, non_camel_case_types)]
|
#[allow(non_snake_case, non_camel_case_types)]
|
||||||
struct #visitor_label;
|
struct #visitor_label;
|
||||||
@ -363,7 +370,10 @@ pub fn parse(
|
|||||||
build_declare_visitor("e! {f64}, "e! {visit_f64}, &visitor_label)
|
build_declare_visitor("e! {f64}, "e! {visit_f64}, &visitor_label)
|
||||||
}
|
}
|
||||||
Some(&FieldType::FieldTypeStruct { ref struct_name }) => {
|
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! {
|
Some(quote! {
|
||||||
#[allow(non_snake_case, non_camel_case_types)]
|
#[allow(non_snake_case, non_camel_case_types)]
|
||||||
struct #visitor_label;
|
struct #visitor_label;
|
||||||
@ -685,7 +695,10 @@ pub fn parse(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
Some(&FieldType::FieldTypeStruct { ref struct_name }) => {
|
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! {
|
Some(quote! {
|
||||||
#label_name => {
|
#label_name => {
|
||||||
reader.set_map_value();
|
reader.set_map_value();
|
||||||
@ -840,7 +853,10 @@ pub fn parse(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
Some(&FieldType::FieldTypeStruct { ref struct_name }) => {
|
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! {
|
Some(quote! {
|
||||||
#label_name => {
|
#label_name => {
|
||||||
reader.set_map_value();
|
reader.set_map_value();
|
||||||
@ -1064,7 +1080,11 @@ pub fn parse(
|
|||||||
}
|
}
|
||||||
Some(FieldType::FieldTypeStruct { struct_name }) => {
|
Some(FieldType::FieldTypeStruct { struct_name }) => {
|
||||||
let struct_ident = Ident::new(
|
let struct_ident = Ident::new(
|
||||||
&format!("__Visitor_{}_{}", label_name, struct_name),
|
&format!(
|
||||||
|
"__Visitor_{}_{}",
|
||||||
|
label_name,
|
||||||
|
struct_name.into_token_stream()
|
||||||
|
),
|
||||||
Span::call_site(),
|
Span::call_site(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -17,48 +17,43 @@ pub enum FieldType {
|
|||||||
FieldTypeF64,
|
FieldTypeF64,
|
||||||
FieldTypeOption { data_type: Box<FieldType> },
|
FieldTypeOption { data_type: Box<FieldType> },
|
||||||
FieldTypeVec { data_type: Box<FieldType> },
|
FieldTypeVec { data_type: Box<FieldType> },
|
||||||
FieldTypeStruct { struct_name: syn::Ident },
|
FieldTypeStruct { struct_name: syn::Path },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FieldType {
|
impl FieldType {
|
||||||
fn from_ident(t: &syn::PathSegment) -> Option<FieldType> {
|
fn from_ident(path: &syn::Path) -> Option<FieldType> {
|
||||||
match t.ident.to_string().as_str() {
|
match path.segments.last() {
|
||||||
"String" => Some(FieldType::FieldTypeString),
|
Some(t) => match t.ident.to_string().as_str() {
|
||||||
"bool" => Some(FieldType::FieldTypeBool),
|
"String" => Some(FieldType::FieldTypeString),
|
||||||
"i8" => Some(FieldType::FieldTypeI8),
|
"bool" => Some(FieldType::FieldTypeBool),
|
||||||
"u8" => Some(FieldType::FieldTypeU8),
|
"i8" => Some(FieldType::FieldTypeI8),
|
||||||
"i16" => Some(FieldType::FieldTypeI16),
|
"u8" => Some(FieldType::FieldTypeU8),
|
||||||
"u16" => Some(FieldType::FieldTypeU16),
|
"i16" => Some(FieldType::FieldTypeI16),
|
||||||
"i32" => Some(FieldType::FieldTypeI32),
|
"u16" => Some(FieldType::FieldTypeU16),
|
||||||
"u32" => Some(FieldType::FieldTypeU32),
|
"i32" => Some(FieldType::FieldTypeI32),
|
||||||
"i64" => Some(FieldType::FieldTypeI64),
|
"u32" => Some(FieldType::FieldTypeU32),
|
||||||
"u64" => Some(FieldType::FieldTypeU64),
|
"i64" => Some(FieldType::FieldTypeI64),
|
||||||
"f32" => Some(FieldType::FieldTypeF32),
|
"u64" => Some(FieldType::FieldTypeU64),
|
||||||
"f64" => Some(FieldType::FieldTypeF64),
|
"f32" => Some(FieldType::FieldTypeF32),
|
||||||
"Option" => get_sub_type(t).map(|data_type| FieldType::FieldTypeOption {
|
"f64" => Some(FieldType::FieldTypeF64),
|
||||||
data_type: Box::new(FieldType::from_ident(&data_type).unwrap()),
|
"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(&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()),
|
||||||
_struct_name => Some(FieldType::FieldTypeStruct {
|
}),
|
||||||
struct_name: t.ident.clone(),
|
_ => Some(FieldType::FieldTypeStruct {
|
||||||
}),
|
struct_name: path.clone(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) => {
|
Path(ref path) => FieldType::from_ident(&path.path),
|
||||||
if path.path.segments.len() != 1 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
match path.path.segments.first() {
|
|
||||||
Some(path_segment) => FieldType::from_ident(path_segment),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user