From 7a3cc3941e825a3d063ab365a51a9b8b1a4e2cbd Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Fri, 26 Jul 2024 21:31:31 +0000 Subject: [PATCH] parse generics for implement macro Signed-off-by: Jason Volk --- src/macros/implement.rs | 34 ++++++++++++++++++++-------------- src/macros/utils.rs | 10 +++++++++- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/macros/implement.rs b/src/macros/implement.rs index b5c8d787..b798bae5 100644 --- a/src/macros/implement.rs +++ b/src/macros/implement.rs @@ -1,26 +1,32 @@ -use proc_macro::TokenStream; +use proc_macro::{Span, TokenStream}; use quote::quote; -use syn::{ItemFn, Meta, MetaList}; +use syn::{Error, ItemFn, Meta, Path}; +use utils::get_named_generics; -use crate::Result; +use crate::{utils, Result}; pub(super) fn implement(item: ItemFn, args: &[Meta]) -> Result { - let Meta::List(MetaList { - path, - .. - }) = &args - .first() - .expect("missing path to trait or item to implement") - else { - panic!("invalid path to item for implement"); - }; - + let generics = get_named_generics(args, "generics")?; + let receiver = get_receiver(args)?; + let params = get_named_generics(args, "params")?; let input = item; let out = quote! { - impl #path { + impl #generics #receiver #params { #input } }; Ok(out.into()) } + +fn get_receiver(args: &[Meta]) -> Result { + let receiver = &args + .first() + .ok_or_else(|| Error::new(Span::call_site().into(), "Missing required argument to receiver"))?; + + let Meta::Path(receiver) = receiver else { + return Err(Error::new(Span::call_site().into(), "First argument is not path to receiver")); + }; + + Ok(receiver.clone()) +} diff --git a/src/macros/utils.rs b/src/macros/utils.rs index 7ae55d39..58074e3a 100644 --- a/src/macros/utils.rs +++ b/src/macros/utils.rs @@ -1,4 +1,12 @@ -use syn::{Expr, Lit, Meta}; +use syn::{parse_str, Expr, Generics, Lit, Meta}; + +use crate::Result; + +pub(crate) fn get_named_generics(args: &[Meta], name: &str) -> Result { + const DEFAULT: &str = "<>"; + + parse_str::(&get_named_string(args, name).unwrap_or_else(|| DEFAULT.to_owned())) +} pub(crate) fn get_named_string(args: &[Meta], name: &str) -> Option { args.iter().find_map(|arg| {