extern crate proc_macro;
use proc_macro::TokenStream;
use proc_macro2::Span;
use proc_macro_crate::{crate_name, FoundCrate};
use quote::quote;
use syn::{parse_macro_input, Ident, ItemStruct};
#[proc_macro_attribute]
pub fn denom(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemStruct);
if !input.fields.is_empty() {
return syn::Error::new_spanned(input, "Struct must be zero-sized")
.to_compile_error()
.into();
}
let name = &input.ident;
let found_crate = crate_name("monetary").expect("Failed to find the `monetary` crate");
let mut derives = vec![
quote! { Clone },
quote! { Debug },
quote! { PartialEq },
quote! { Eq },
quote! { PartialOrd },
quote! { Ord },
quote! { Copy },
quote! { Default },
];
#[cfg(feature = "serde")]
match &found_crate {
FoundCrate::Itself => {
derives.push(quote! { crate::__derive_import::serde::Serialize });
derives.push(quote! { crate::__derive_import::serde::Deserialize });
}
FoundCrate::Name(crate_name) => {
let ident = Ident::new(crate_name, Span::call_site());
derives.push(quote! { #ident::__derive_import::serde::Serialize });
derives.push(quote! { #ident::__derive_import::serde::Deserialize });
}
}
#[cfg(feature = "schemars")]
match &found_crate {
FoundCrate::Itself => {
derives.push(quote! { crate::__derive_import::schemars::JsonSchema });
}
FoundCrate::Name(crate_name) => {
let ident = Ident::new(crate_name, Span::call_site());
derives.push(quote! { #ident::__derive_import::schemars::JsonSchema });
}
}
let derives = quote! { #[derive(#(#derives),*)] };
let trait_impl = match found_crate {
FoundCrate::Itself => quote! {
unsafe impl crate::Denomination for #name {}
},
FoundCrate::Name(crate_name) => {
let ident = Ident::new(&crate_name, Span::call_site());
quote! {
unsafe impl #ident::Denomination for #name {}
}
}
};
let expanded = quote! {
#derives
#input
#trait_impl
};
TokenStream::from(expanded)
}