tyzen-macro 0.1.10

Procedural macros for the tyzen crate.
Documentation
use proc_macro::TokenStream;
use quote::quote;
use syn::{DeriveInput, Expr, Lit, LitStr, parse_macro_input};

use crate::type_derive::case::{RenameRule, apply_rename_rule};

pub fn event(attr: TokenStream, item: TokenStream) -> TokenStream {
    let mut input = parse_macro_input!(item as DeriveInput);
    let event_name = parse_macro_input!(attr as LitStr);

    input
        .attrs
        .push(syn::parse_quote! { #[tyzen(name = #event_name)] });
    input
        .attrs
        .push(syn::parse_quote! { #[derive(::tyzen::Event)] });
    input
        .attrs
        .push(syn::parse_quote! { #[event(#event_name)] });

    quote! {
        #input
    }
    .into()
}

pub fn derive_event(item: TokenStream) -> TokenStream {
    let input = parse_macro_input!(item as DeriveInput);

    // Check for #[tyzen(name = "...")]
    let mut custom_name = None;
    for attr in &input.attrs {
        if attr.path().is_ident("tyzen") {
            let _ = attr.parse_nested_meta(|meta| {
                if meta.path.is_ident("name") {
                    let value = meta.value()?;
                    let expr: Expr = value.parse()?;
                    if let Expr::Lit(expr_lit) = expr
                        && let Lit::Str(lit_str) = expr_lit.lit
                    {
                        custom_name = Some(lit_str.value());
                    }
                }
                Ok(())
            });
        }
    }

    let name = if let Some(n) = custom_name {
        n
    } else {
        let mut s = input.ident.to_string();
        if s.ends_with("Event") {
            s.truncate(s.len() - 5);
        }
        apply_rename_rule(&s, RenameRule::KebabCase)
    };

    let struct_name = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let expanded = quote! {
        impl #impl_generics #struct_name #ty_generics #where_clause {
            pub fn emit<R: ::tauri::Runtime>(&self, handle: &impl ::tauri::Emitter<R>) -> ::tauri::Result<()> {
                handle.emit(#name, self)
            }
        }

        ::tyzen::__private::inventory::submit! {
            ::tyzen::EventMeta {
                name: #name,
                payload_type: <#struct_name #ty_generics as ::tyzen::TsType>::ts_name,
            }
        }
    };

    TokenStream::from(expanded)
}