defmt-macros 1.1.1

defmt macros
Documentation
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::{parse_macro_input, Fields, ItemStruct};

pub(crate) fn expand(args: TokenStream, item: TokenStream) -> TokenStream {
    let strukt = parse_macro_input!(item as ItemStruct);

    if !args.is_empty() {
        return syn::Error::new(
            Span::call_site(),
            "`#[global_logger]` attribute takes no arguments",
        )
        .into_compile_error()
        .into();
    }

    if let Err(err) = validate(&strukt) {
        return err.into_compile_error().into();
    }

    codegen(&strukt)
}

fn validate(strukt: &ItemStruct) -> syn::Result<()> {
    let is_unit_struct = matches!(strukt.fields, Fields::Unit);

    if !strukt.generics.params.is_empty()
        || strukt.generics.where_clause.is_some()
        || !is_unit_struct
    {
        Err(syn::Error::new(
            strukt.ident.span(),
            "struct must be a non-generic unit struct (e.g. `struct S;`)",
        ))
    } else {
        Ok(())
    }
}

fn codegen(strukt: &ItemStruct) -> TokenStream {
    let attrs = &strukt.attrs;
    let ident = &strukt.ident;
    let vis = &strukt.vis;

    quote!(
        #(#attrs)*
        #vis struct #ident;

        #[inline(never)]
        #[no_mangle]
        unsafe fn _defmt_acquire()  {
            <#ident as defmt::Logger>::acquire()
        }

        #[inline(never)]
        #[no_mangle]
        unsafe fn _defmt_flush()  {
            <#ident as defmt::Logger>::flush()
        }

        #[inline(never)]
        #[no_mangle]
        unsafe fn _defmt_release()  {
            <#ident as defmt::Logger>::release()
        }

        #[inline(never)]
        #[no_mangle]
        unsafe fn _defmt_write(bytes: &[u8])  {
            <#ident as defmt::Logger>::write(bytes)
        }
    )
    .into()
}