use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::{Ident, ItemTrait, TraitBound, parse_macro_input, punctuated::Punctuated, token::Plus};
pub fn generate(args: TokenStream, input: TokenStream) -> TokenStream {
let product_trait = parse_macro_input!(input as ItemTrait);
let product_bounds = if args.is_empty() {
Punctuated::<TraitBound, Plus>::new()
} else {
parse_macro_input!(args with Punctuated::<TraitBound, Plus>::parse_terminated)
};
let product_vis = &product_trait.vis;
let product_ident = &product_trait.ident;
let factory_ident = Ident::new(&format!("{product_ident}Factory"), Span::call_site());
let bounds_iter = product_bounds.iter();
let product_type = quote! { dyn #product_ident #( + #bounds_iter )* };
quote! {
#product_trait
#product_vis struct #factory_ident;
impl #factory_ident {
#[inline]
pub fn create(
id: impl AsRef<str>,
strategy: ::rust_patterns::FactoryFallback,
) -> std::result::Result<Box<#product_type>, ::rust_patterns::FactoryError> {
static FACTORY: ::std::sync::LazyLock<::rust_patterns::SimpleFactory<#product_type>> =
::std::sync::LazyLock::new(::rust_patterns::FactoryRegistry::simple_factory);
FACTORY.create(id, strategy)
}
}
}
.into()
}