mini-internal-miku 0.1.23

Derive macros for miniserde. Use the re-exports from the miniserde crate instead.
Documentation
use crate::{attr, bound};
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{
    parse_quote, Data, DataEnum, DataStruct, DeriveInput, Error, Fields, FieldsNamed, Ident, Result,
};

pub fn derive(input: DeriveInput) -> Result<TokenStream> {
    match &input.data {
        Data::Struct(DataStruct {
            fields: Fields::Named(fields),
            ..
        }) => derive_struct(&input, fields),
        Data::Enum(enumeration) => derive_enum(&input, enumeration),
        Data::Struct(_) => Err(Error::new(
            Span::call_site(),
            "currently only structs with named fields are supported",
        )),
        Data::Union(_) => Err(Error::new(
            Span::call_site(),
            "currently only structs and enums are supported by this derive",
        )),
    }
}

pub fn derive_struct(input: &DeriveInput, fields: &FieldsNamed) -> Result<TokenStream> {
    let ident = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    let dummy = Ident::new(
        &format!("_IMPL_MINIDESERIALIZE_FOR_{}", ident),
        Span::call_site(),
    );

    let fieldname = fields.named.iter().map(|f| &f.ident).collect::<Vec<_>>();
    let fieldty = fields.named.iter().map(|f| &f.ty);
    let fieldstr = fields
        .named
        .iter()
        .map(attr::name_of_field)
        .collect::<Result<Vec<_>>>()?;

    let wrapper_generics = bound::with_lifetime_bound(&input.generics, "'__a");
    let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
    let bound = parse_quote!(miniserde_miku::Deserialize);
    let bounded_where_clause = bound::where_clause_with_bound(&input.generics, bound);

    Ok(quote! {
        #[allow(non_upper_case_globals)]
        const #dummy: () = {
            #[repr(C)]
            struct __Visitor #impl_generics #where_clause {
                __out: miniserde_miku::__private::Option<#ident #ty_generics>,
            }

            impl #impl_generics miniserde_miku::Deserialize for #ident #ty_generics #bounded_where_clause {
                fn begin(__out: &mut miniserde_miku::__private::Option<Self>) -> &mut dyn miniserde_miku::de::Visitor {
                    unsafe {
                        &mut *{
                            __out
                            as *mut miniserde_miku::__private::Option<Self>
                            as *mut __Visitor #ty_generics
                        }
                    }
                }
            }

            impl #impl_generics miniserde_miku::de::Visitor for __Visitor #ty_generics #bounded_where_clause {
                fn map(&mut self) -> miniserde_miku::Result<miniserde_miku::__private::Box<dyn miniserde_miku::de::Map + '_>> {
                    Ok(miniserde_miku::__private::Box::new(__State {
                        #(
                            #fieldname: miniserde_miku::Deserialize::default(),
                        )*
                        __out: &mut self.__out,
                    }))
                }
            }

            struct __State #wrapper_impl_generics #where_clause {
                #(
                    #fieldname: miniserde_miku::__private::Option<#fieldty>,
                )*
                __out: &'__a mut miniserde_miku::__private::Option<#ident #ty_generics>,
            }

            impl #wrapper_impl_generics miniserde_miku::de::Map for __State #wrapper_ty_generics #bounded_where_clause {
                fn key(&mut self, __k: &miniserde_miku::__private::str) -> miniserde_miku::Result<&mut dyn miniserde_miku::de::Visitor> {
                    match __k {
                        #(
                            #fieldstr => miniserde_miku::__private::Ok(miniserde_miku::Deserialize::begin(&mut self.#fieldname)),
                        )*
                        _ => miniserde_miku::__private::Ok(<dyn miniserde_miku::de::Visitor>::ignore()),
                    }
                }

                fn finish(&mut self) -> miniserde_miku::Result<()> {
                    #(
                        let #fieldname = self.#fieldname.take().ok_or(miniserde_miku::Error)?;
                    )*
                    *self.__out = miniserde_miku::__private::Some(#ident {
                        #(
                            #fieldname,
                        )*
                    });
                    miniserde_miku::__private::Ok(())
                }
            }
        };
    })
}

pub fn derive_enum(input: &DeriveInput, enumeration: &DataEnum) -> Result<TokenStream> {
    if input.generics.lt_token.is_some() || input.generics.where_clause.is_some() {
        return Err(Error::new(
            Span::call_site(),
            "Enums with generics are not supported",
        ));
    }

    let ident = &input.ident;
    let dummy = Ident::new(
        &format!("_IMPL_MINIDESERIALIZE_FOR_{}", ident),
        Span::call_site(),
    );

    let var_idents = enumeration
        .variants
        .iter()
        .map(|variant| match variant.fields {
            Fields::Unit => Ok(&variant.ident),
            _ => Err(Error::new_spanned(
                variant,
                "Invalid variant: only simple enum variants without fields are supported",
            )),
        })
        .collect::<Result<Vec<_>>>()?;
    let names = enumeration
        .variants
        .iter()
        .map(attr::name_of_variant)
        .collect::<Result<Vec<_>>>()?;

    Ok(quote! {
        #[allow(non_upper_case_globals)]
        const #dummy: () = {
            #[repr(C)]
            struct __Visitor {
                __out: miniserde_miku::__private::Option<#ident>,
            }

            impl miniserde_miku::Deserialize for #ident {
                fn begin(__out: &mut miniserde_miku::__private::Option<Self>) -> &mut dyn miniserde_miku::de::Visitor {
                    unsafe {
                        &mut *{
                            __out
                            as *mut miniserde_miku::__private::Option<Self>
                            as *mut __Visitor
                        }
                    }
                }
            }

            impl miniserde_miku::de::Visitor for __Visitor {
                fn string(&mut self, s: &miniserde_miku::__private::str) -> miniserde_miku::Result<()> {
                    let value = match s {
                        #( #names => #ident::#var_idents, )*
                        _ => return miniserde_miku::__private::Err(miniserde_miku::Error),
                    };
                    self.__out = miniserde_miku::__private::Some(value);
                    miniserde_miku::__private::Ok(())
                }
            }
        };
    })
}