wire_weaver_derive 0.4.0

Derive macros of wire_weaver - API code generator for microcontrollers
Documentation
use convert_case::{Case, Casing};
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
use syn::{Error, ItemTrait};
use wire_weaver_core::ast::api::ApiLevelSourceLocation;
use wire_weaver_core::transform::transform_api_level::transform_api_level;

pub fn ww_trait(attr: TokenStream, item: TokenStream) -> TokenStream {
    ww_trait_inner(attr, item)
        .unwrap_or_else(|e| Error::new(Span::call_site(), e).to_compile_error())
}

fn ww_trait_inner(_attr: TokenStream, item: TokenStream) -> Result<TokenStream, Error> {
    let item_trait: ItemTrait = syn::parse2(item)?;
    let api_level = transform_api_level(
        &item_trait,
        ApiLevelSourceLocation::File {
            path: Default::default(),
            part_of_crate: Ident::new("dummy", Span::call_site()),
        },
    )
    .map_err(|e| Error::new(Span::call_site(), e))?;

    let trait_name = item_trait.ident.to_string();
    let mut check_types_lifetimes = TokenStream::new();
    for (ty, lifetime) in api_level.external_types() {
        let check_name = if lifetime {
            "ShouldHaveALifetime"
        } else {
            "ShouldNotHaveALifetime"
        };
        let Some(last) = ty.segments.last() else {
            continue;
        };
        let check_name = Ident::new(
            format!("_{trait_name}{last}{check_name}",).as_str(),
            last.span(),
        );
        let ty = &ty;
        if lifetime {
            check_types_lifetimes.extend(quote! {
                type #check_name<'i> = #ty<'i>;
            });
        } else {
            check_types_lifetimes.extend(quote! {
                type #check_name = #ty;
            });
        }
    }

    let docs: Vec<_> = item_trait
        .attrs
        .iter()
        .filter(|a| a.path().is_ident("doc"))
        .collect();
    let full_gid = Ident::new(
        format!("{}_FULL_GID", item_trait.ident)
            .to_case(Case::Constant)
            .as_str(),
        item_trait.ident.span(),
    );
    Ok(quote! {
        #(#docs)*
        pub const #full_gid: ww_version::FullVersion = wire_weaver::full_version!();
        #check_types_lifetimes
    })
}