microtype-macro 0.2.5

Proc macro for generating microtypes
Documentation
use super::{
    special_attrs::{generate_int_impls, string_impls, SpecialAttrs, TypeAnnotation},
    HAS_DEREF_IMPLS, HAS_SERDE,
};
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Attribute, Ident, Type, Visibility};

fn generate_struct(name: &Ident, vis: &Visibility, inner: &Type) -> TokenStream {
    quote! {
        #[repr(transparent)]
        #vis struct #name(pub #inner);
    }
}

fn generate_microtype_impl(name: &Ident, inner: &Type) -> TokenStream {
    quote! {
        impl ::microtype::Microtype for #name {
            type Inner = #inner;

            fn new(inner: Self::Inner) -> Self {
                Self(inner)
            }

            fn into_inner(self) -> Self::Inner {
                self.0
            }

            fn inner(&self) -> &Self::Inner {
                &self.0
            }

            fn inner_mut(&mut self) -> &mut Self::Inner {
                &mut self.0
            }


            fn convert<T: ::microtype::Microtype<Inner = Self::Inner>>(self) -> T {
                T::new(self.0)
            }
        }
    }
}

fn generate_from_impl(name: &Ident, inner: &Type) -> TokenStream {
    quote! {
        impl ::std::convert::From<#inner> for #name {
            fn from(inner: #inner) -> Self {
                Self(inner)
            }
        }
    }
}

fn generate_deref_impl(name: &Ident, inner: &Type) -> TokenStream {
    if HAS_DEREF_IMPLS {
        quote! {
            impl ::core::ops::Deref for #name {
                type Target = #inner;

                fn deref(&self) -> &Self::Target {
                    &self.0
                }
            }

            impl ::core::ops::DerefMut for #name {
                fn deref_mut(&mut self) -> &mut Self::Target {
                    &mut self.0
                }
            }
        }
    } else {
        quote! {}
    }
}

fn serde_derives() -> TokenStream {
    if HAS_SERDE {
        quote! {
            #[derive(::serde::Deserialize, ::serde::Serialize)]
            #[serde(transparent)]
        }
    } else {
        quote! {}
    }
}

pub fn generate_normal(
    inner: Type,
    name: Ident,
    vis: Visibility,
    attrs: Vec<Attribute>,
    special_attrs: SpecialAttrs,
) -> TokenStream {
    let struct_def = generate_struct(&name, &vis, &inner);
    let microtype_impl = generate_microtype_impl(&name, &inner);
    let from_impl = generate_from_impl(&name, &inner);
    let deref_impl = generate_deref_impl(&name, &inner);
    let serde_attrs = serde_derives();

    let type_specific_impls = match special_attrs.type_annotation {
        None => quote! {},
        Some(TypeAnnotation::String) => string_impls(&name, &inner),
        Some(TypeAnnotation::Int) => generate_int_impls(&name, &inner),
    };

    quote! {
        #(#attrs)*
        #serde_attrs
        #struct_def

        #microtype_impl

        #from_impl
        #deref_impl
        #type_specific_impls
    }
}