jacklog-macro 0.4.0

Easy way to get logging the way Jack always wants anyway
Documentation
use proc_macro::TokenStream;
use quote::quote;
use syn::{
    parse_macro_input, Data::Struct, DataStruct, DeriveInput, Fields::Named,
    FieldsNamed,
};

#[proc_macro_attribute]
pub fn verbose(_attr: TokenStream, item: TokenStream) -> TokenStream {
    let ast = parse_macro_input!(item as DeriveInput);
    let vis = ast.vis;
    let name = ast.ident;
    let attrs = &ast.attrs;

    // Get the named fields out of the struct.
    let Struct(DataStruct {
        fields:
            Named(FieldsNamed {
                ref named,
                ..
            }),
        ..
    }) = ast.data
    else {
        unimplemented!("only works on structs");
    };

    // Go through all the fields and collect them so we can output them again.
    let builder_fields = named.iter().map(|f| {
        let name = &f.ident;
        let ty = &f.ty;
        let attrs = &f.attrs;
        let vis = &f.vis;

        quote! {
            #(#attrs)*
            #vis #name: #ty
        }
    });

    // Re-output the original struct, but with the added verbose field.
    let decorated = quote! {
        #(#attrs)*
        #vis struct #name {
            /// Increase verbosity from the baseline of WARN.
            ///
            /// Passing additional -v arguments will continue increasing
            /// verbosity. For more sophisticated logging requirements, use the
            /// RUST_LOG environment variable, which will override this setting.
            #[clap(short, long, action = ::clap::ArgAction::Count, global = true)]
            // TODO: accept a parameter for visibility.
            #vis verbose: u8,

            #(#builder_fields,)*
        }
    };

    decorated.into()
}