quickvariant_macros/
lib.rs

1use syn::punctuated::Punctuated;
2
3#[proc_macro]
4pub fn make_variant(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
5    if input.is_empty() {
6        return syn::Error::new_spanned(
7            proc_macro2::TokenStream::from(input),
8            "Macro input cannot be empty. Please specify at least one type."
9        ).to_compile_error().into();
10    }
11    let types = syn::parse_macro_input!(
12        input with Punctuated::<syn::Type, syn::token::Comma>::parse_terminated
13    );
14    let sizes = types.iter().map(|ty| {
15        quote::quote! { std::mem::size_of::<#ty>() }
16    });
17    let aligns = types.iter().map(|ty| {
18        quote::quote! { std::mem::align_of::<#ty>() }
19    });
20    let ids = types.iter().map(|ty| {
21        quote::quote! { std::any::TypeId::of::<#ty>() }
22    });
23    let errmsg = syn::LitStr::new(
24        "Macro input cannot be empty. Please specify at least one type.",
25        proc_macro2::Span::call_site()
26    );
27    quote::quote! {
28        {
29            let max_size = [#(#sizes),*].iter().copied().max().expect(#errmsg);
30            let max_align = [#(#aligns),*].iter().copied().max().expect(#errmsg);
31            let mut types = std::collections::HashSet::new();
32            for ty in [#(#ids),*] {
33                types.insert(ty);
34            }
35            quickvariant::Variant::__new(max_size, max_align, types)
36        }
37    }.into()
38}