sword-macros 0.3.0

Structured web framework built on top of tokio ecosystem, providing powerful features for building robust web applications.
Documentation
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{DeriveInput, Error, Expr, Lit, Meta};

pub fn expand_event_struct(args: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
    let input = syn::parse::<DeriveInput>(item)?;

    if !matches!(input.data, syn::Data::Struct(_)) {
        return Err(syn::Error::new_spanned(
            &input,
            "#[event] can only be applied to structs",
        ));
    }

    let struct_name = &input.ident;
    let meta = syn::parse::<Meta>(args)?;

    let nv = meta.require_name_value().map_err(|_| {
        Error::new_spanned(&meta, r#"expected format: #[event(key = "event.key"])"#)
    })?;

    if !nv.path.is_ident("key") {
        return Err(Error::new_spanned(&nv.path, "expected `key` attribute"));
    }

    let Expr::Lit(expr_lit) = &nv.value else {
        return Err(Error::new_spanned(
            &nv.value,
            "expected string literal for key",
        ));
    };

    let Lit::Str(lit_str) = &expr_lit.lit else {
        return Err(Error::new_spanned(
            &expr_lit.lit,
            "expected string literal for key",
        ));
    };

    let key = lit_str.value();

    let expanded: TokenStream2 = quote! {
        #[derive(::std::clone::Clone, ::std::fmt::Debug)]
        #input

        impl ::sword::internal::events::Event for #struct_name {
            fn key(&self) -> &'static str {
                #key
            }

            fn clone_event(&self) -> ::std::boxed::Box<dyn ::sword::internal::events::Event> {
                ::std::boxed::Box::new(self.clone())
            }
        }
    };

    Ok(TokenStream::from(expanded))
}