architect-derive 0.4.0

Architect.xyz Trading Platform API, proc-macros
Documentation
use proc_macro::TokenStream;
use quote::quote;
use syn::{
    parse_macro_input, punctuated::Punctuated, Data, DeriveInput, Fields, Meta, Token,
};

pub fn derive_newtype(input: TokenStream) -> TokenStream {
    let DeriveInput { ident, data, attrs, .. } = parse_macro_input!(input);
    let mut derive_deref = false;
    let mut derive_deref_mut = false;
    let mut derive_from = false;
    // parse attributes
    for attr in attrs {
        if attr.meta.path().is_ident("newtype") {
            let nested = attr
                .parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
                .unwrap();
            for meta in nested {
                if meta.path().is_ident("Deref") {
                    derive_deref = true;
                } else if meta.path().is_ident("DerefMut") {
                    derive_deref_mut = true;
                } else if meta.path().is_ident("From") {
                    derive_from = true;
                }
            }
        }
    }
    let mut impls = Vec::new();
    let inner = match data {
        Data::Struct(data) => match data.fields {
            Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
                fields.unnamed.first().unwrap().ty.clone()
            }
            _ => panic!("expecting a unit newtype struct"),
        },
        _ => panic!("expecting a unit newtype struct"),
    };
    if derive_deref {
        impls.push(quote! {
            impl std::ops::Deref for #ident {
                type Target = #inner;

                fn deref(&self) -> &Self::Target {
                    &self.0
                }
            }
        });
    }
    if derive_deref_mut {
        impls.push(quote! {
            impl std::ops::DerefMut for #ident {
                fn deref_mut(&mut self) -> &mut Self::Target {
                    &mut self.0
                }
            }
        });
    }
    if derive_from {
        impls.push(quote! {
            impl From<#inner> for #ident {
                fn from(inner: #inner) -> Self {
                    Self(inner)
                }
            }
        });
    }
    let expanded = quote! {
        #(#impls)*
    };
    TokenStream::from(expanded)
}