Use serde internals to determine property names
This commit is contained in:
parent
2592fa388f
commit
48d6cda0b8
1 changed files with 29 additions and 22 deletions
|
@ -4,21 +4,27 @@ extern crate quote;
|
||||||
extern crate syn;
|
extern crate syn;
|
||||||
|
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
extern crate proc_macro2;
|
|
||||||
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::{Span, TokenStream};
|
||||||
|
use serde_derive_internals::ast::{Container, Data, Field, Style, Variant};
|
||||||
|
use serde_derive_internals::{Ctxt, Derive};
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::{Data, DeriveInput, Fields};
|
use syn::DeriveInput;
|
||||||
|
|
||||||
#[proc_macro_derive(MakeSchema, attributes(schemars, serde))]
|
#[proc_macro_derive(MakeSchema, attributes(schemars, serde))]
|
||||||
pub fn derive_make_schema(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn derive_make_schema(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
|
let ctxt = Ctxt::new();
|
||||||
|
let cont = Container::from_ast(&ctxt, &input, Derive::Deserialize);
|
||||||
|
if let Err(e) = ctxt.check() {
|
||||||
|
return compile_error(input.span(), e).into();
|
||||||
|
}
|
||||||
|
|
||||||
let name = input.ident;
|
let name = cont.ident;
|
||||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
let (impl_generics, ty_generics, where_clause) = cont.generics.split_for_impl();
|
||||||
|
|
||||||
let fn_contents = match input.data {
|
let fn_contents = match cont.data {
|
||||||
Data::Struct(data) => struct_implementation(&data.fields),
|
Data::Struct(Style::Struct, ref fields) => struct_implementation(fields),
|
||||||
_ => unimplemented!("Only structs work so far!"),
|
_ => unimplemented!("Only structs work so far!"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,20 +43,21 @@ pub fn derive_make_schema(input: proc_macro::TokenStream) -> proc_macro::TokenSt
|
||||||
proc_macro::TokenStream::from(impl_block)
|
proc_macro::TokenStream::from(impl_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn struct_implementation(fields: &Fields) -> TokenStream {
|
fn compile_error(span: Span, message: String) -> TokenStream {
|
||||||
match fields {
|
quote_spanned! {span=>
|
||||||
Fields::Named(ref fields) => {
|
compile_error!(#message);
|
||||||
let recurse = fields.named.iter().map(|f| {
|
}
|
||||||
let name = (&f.ident).as_ref().map(ToString::to_string);
|
}
|
||||||
let ty = &f.ty;
|
|
||||||
quote_spanned! {f.span()=>
|
fn struct_implementation(fields: &[Field]) -> TokenStream {
|
||||||
|
let recurse = fields.into_iter().map(|f| {
|
||||||
|
let name = f.attrs.name().deserialize_name();
|
||||||
|
let ty = f.ty;
|
||||||
|
quote_spanned! {f.original.span()=>
|
||||||
o.properties.insert(#name.to_owned(), gen.subschema_for::<#ty>());
|
o.properties.insert(#name.to_owned(), gen.subschema_for::<#ty>());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
quote! {
|
quote! {
|
||||||
#(#recurse)*
|
#(#recurse)*
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => unimplemented!("Only named fields work so far!"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue