mod tests;
use super::ItemType;
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Fields, Ident};
pub fn derive(item: &DeriveInput) -> TokenStream {
let fields: &Fields = if let Data::Struct(s) = &item.data {
&s.fields
} else {
panic!("Only structs are supported");
};
let item_ident = &item.ident;
let seq_body = generate_seq_body(item_ident, fields);
let body = generate_body(item_ident, fields);
quote! {
impl<'de> serde::de::Deserialize<'de> for #item_ident {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = #item_ident;
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
formatter.write_str(stringify!(struct #item_ident))
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
#seq_body
}
}
#body
}
}
}
}
fn generate_body(item_ident: &Ident, fields: &Fields) -> TokenStream {
match fields {
Fields::Unnamed(..) | Fields::Named(..) => quote! {
deserializer.deserialize_tuple_struct(stringify!(#item_ident), usize::MAX, Visitor)
},
Fields::Unit => {
quote! {
deserializer.deserialize_unit_struct(stringify!(#item_ident), Visitor)
}
}
}
}
fn generate_seq_body(ident: &Ident, fields: &Fields) -> TokenStream {
match &fields {
syn::Fields::Named(fields_named) => super::generate_named_fields_deserialization(ident, ItemType::Struct, fields_named),
syn::Fields::Unnamed(fields_unnamed) => super::generate_unnamed_fields_deserialization(ident, ItemType::Struct, fields_unnamed),
syn::Fields::Unit => quote! {Ok(#ident)},
}
}