From 0f2756536e8fc311119da2af5b4dcc33f41bec6e Mon Sep 17 00:00:00 2001 From: HampusM Date: Wed, 4 Oct 2023 12:51:06 +0200 Subject: refactor!: remove factory & declare_default_factory macros BREAKING CHANGE: The factory and the declare_default_factory macros have been removed. They are no longer needed to use factories --- macros/src/factory/build_declare_interfaces.rs | 52 ------ macros/src/factory/declare_default_args.rs | 232 ------------------------- macros/src/factory/macro_args.rs | 106 ----------- macros/src/factory/mod.rs | 4 - macros/src/factory/type_alias.rs | 68 -------- macros/src/fn_trait.rs | 162 ----------------- macros/src/lib.rs | 158 ----------------- 7 files changed, 782 deletions(-) delete mode 100644 macros/src/factory/build_declare_interfaces.rs delete mode 100644 macros/src/factory/declare_default_args.rs delete mode 100644 macros/src/factory/macro_args.rs delete mode 100644 macros/src/factory/mod.rs delete mode 100644 macros/src/factory/type_alias.rs delete mode 100644 macros/src/fn_trait.rs (limited to 'macros/src') diff --git a/macros/src/factory/build_declare_interfaces.rs b/macros/src/factory/build_declare_interfaces.rs deleted file mode 100644 index 1e2d62e..0000000 --- a/macros/src/factory/build_declare_interfaces.rs +++ /dev/null @@ -1,52 +0,0 @@ -use proc_macro2::TokenStream; -use quote::quote; - -use crate::fn_trait::FnTrait; - -pub fn build_declare_factory_interfaces( - factory_interface: &FnTrait, - is_threadsafe: bool, -) -> TokenStream -{ - if is_threadsafe { - quote! { - syrette::declare_interface!( - syrette::private::castable_factory::threadsafe::ThreadsafeCastableFactory< - #factory_interface, - syrette::di_container::asynchronous::AsyncDIContainer, - > -> syrette::private::factory::IThreadsafeFactory< - #factory_interface, - syrette::di_container::asynchronous::AsyncDIContainer, - >, - threadsafe_sharable = true - ); - - syrette::declare_interface!( - syrette::private::castable_factory::threadsafe::ThreadsafeCastableFactory< - #factory_interface, - syrette::di_container::asynchronous::AsyncDIContainer, - > -> syrette::private::any_factory::AnyThreadsafeFactory, - threadsafe_sharable = true - ); - } - } else { - quote! { - syrette::declare_interface!( - syrette::private::castable_factory::CastableFactory< - #factory_interface, - syrette::di_container::blocking::DIContainer - > -> syrette::private::factory::IFactory< - #factory_interface, - syrette::di_container::blocking::DIContainer - > - ); - - syrette::declare_interface!( - syrette::private::castable_factory::CastableFactory< - #factory_interface, - syrette::di_container::blocking::DIContainer - > -> syrette::private::any_factory::AnyFactory - ); - } - } -} diff --git a/macros/src/factory/declare_default_args.rs b/macros/src/factory/declare_default_args.rs deleted file mode 100644 index 9930f4f..0000000 --- a/macros/src/factory/declare_default_args.rs +++ /dev/null @@ -1,232 +0,0 @@ -use syn::parse::Parse; -use syn::punctuated::Punctuated; -use syn::{Token, Type}; - -use crate::macro_flag::MacroFlag; -use crate::util::iterator_ext::IteratorExt; - -pub const FACTORY_MACRO_FLAGS: &[&str] = &["threadsafe", "async"]; - -pub struct DeclareDefaultFactoryMacroArgs -{ - pub interface: Type, - pub flags: Punctuated, -} - -impl Parse for DeclareDefaultFactoryMacroArgs -{ - fn parse(input: syn::parse::ParseStream) -> syn::Result - { - let interface = input.parse()?; - - if !input.peek(Token![,]) { - return Ok(Self { - interface, - flags: Punctuated::new(), - }); - } - - input.parse::()?; - - let flags = Punctuated::::parse_terminated(input)?; - - for flag in &flags { - let name = flag.name().to_string(); - - if !FACTORY_MACRO_FLAGS.contains(&name.as_str()) { - return Err(input.error(format!( - "Unknown flag '{name}'. Expected one of [ {} ]", - FACTORY_MACRO_FLAGS.join(",") - ))); - } - } - - let flag_names = flags - .iter() - .map(|flag| flag.name().to_string()) - .collect::>(); - - if let Some((dupe_flag_name, _)) = flag_names.iter().find_duplicate() { - return Err(input.error(format!("Duplicate flag '{dupe_flag_name}'"))); - } - - Ok(Self { interface, flags }) - } -} - -#[cfg(test)] -mod tests -{ - use proc_macro2::Span; - use quote::{format_ident, quote}; - use syn::token::Dyn; - use syn::{ - parse2, - Lit, - LitBool, - Path, - PathArguments, - PathSegment, - TraitBound, - TraitBoundModifier, - Type, - TypeParamBound, - TypeTraitObject, - }; - - use super::*; - use crate::macro_flag::MacroFlagValue; - - #[test] - fn can_parse_with_interface_only() - { - let input_args = quote! { - dyn IFoo - }; - - let dec_def_fac_args = - parse2::(input_args).unwrap(); - - assert_eq!( - dec_def_fac_args.interface, - Type::TraitObject(TypeTraitObject { - dyn_token: Some(Dyn::default()), - bounds: Punctuated::from_iter(vec![TypeParamBound::Trait(TraitBound { - paren_token: None, - modifier: TraitBoundModifier::None, - lifetimes: None, - path: Path { - leading_colon: None, - segments: Punctuated::from_iter(vec![PathSegment { - ident: format_ident!("IFoo"), - arguments: PathArguments::None - }]) - } - })]) - }) - ); - - assert!(dec_def_fac_args.flags.is_empty()); - } - - #[test] - fn can_parse_with_interface_and_single_flag() - { - let input_args = quote! { - dyn IBar, threadsafe = true - }; - - let dec_def_fac_args = - parse2::(input_args).unwrap(); - - assert_eq!( - dec_def_fac_args.interface, - Type::TraitObject(TypeTraitObject { - dyn_token: Some(Dyn::default()), - bounds: Punctuated::from_iter(vec![TypeParamBound::Trait(TraitBound { - paren_token: None, - modifier: TraitBoundModifier::None, - lifetimes: None, - path: Path { - leading_colon: None, - segments: Punctuated::from_iter(vec![PathSegment { - ident: format_ident!("IBar"), - arguments: PathArguments::None - }]) - } - })]) - }) - ); - - assert_eq!( - dec_def_fac_args.flags, - Punctuated::from_iter(vec![MacroFlag { - name: format_ident!("threadsafe"), - value: MacroFlagValue::Literal(Lit::Bool(LitBool::new( - true, - Span::call_site() - ))) - }]) - ); - } - - #[test] - fn can_parse_with_interface_and_multiple_flags() - { - let input_args = quote! { - dyn IBar, threadsafe = true, async = false - }; - - let dec_def_fac_args = - parse2::(input_args).unwrap(); - - assert_eq!( - dec_def_fac_args.interface, - Type::TraitObject(TypeTraitObject { - dyn_token: Some(Dyn::default()), - bounds: Punctuated::from_iter(vec![TypeParamBound::Trait(TraitBound { - paren_token: None, - modifier: TraitBoundModifier::None, - lifetimes: None, - path: Path { - leading_colon: None, - segments: Punctuated::from_iter(vec![PathSegment { - ident: format_ident!("IBar"), - arguments: PathArguments::None - }]) - } - })]) - }) - ); - - assert_eq!( - dec_def_fac_args.flags, - Punctuated::from_iter(vec![ - MacroFlag { - name: format_ident!("threadsafe"), - value: MacroFlagValue::Literal(Lit::Bool(LitBool::new( - true, - Span::call_site() - ))) - }, - MacroFlag { - name: format_ident!("async"), - value: MacroFlagValue::Literal(Lit::Bool(LitBool::new( - false, - Span::call_site() - ))) - } - ]) - ); - } - - #[test] - fn cannot_parse_with_interface_and_invalid_flag() - { - let input_args = quote! { - dyn IBar, async = true, foo = false - }; - - assert!(parse2::(input_args).is_err()); - } - - #[test] - fn cannot_parse_with_interface_and_duplicate_flag() - { - assert!( - // Formatting is weird without this comment - parse2::(quote! { - dyn IBar, async = true, threadsafe = false, async = true - }) - .is_err() - ); - - assert!( - // Formatting is weird without this comment - parse2::(quote! { - dyn IBar, async = true, threadsafe = false, async = false - }) - .is_err() - ); - } -} diff --git a/macros/src/factory/macro_args.rs b/macros/src/factory/macro_args.rs deleted file mode 100644 index 676b412..0000000 --- a/macros/src/factory/macro_args.rs +++ /dev/null @@ -1,106 +0,0 @@ -use syn::parse::Parse; -use syn::punctuated::Punctuated; -use syn::Token; - -use crate::macro_flag::MacroFlag; -use crate::util::iterator_ext::IteratorExt; - -pub const FACTORY_MACRO_FLAGS: &[&str] = &["threadsafe"]; - -pub struct FactoryMacroArgs -{ - pub flags: Punctuated, -} - -impl Parse for FactoryMacroArgs -{ - fn parse(input: syn::parse::ParseStream) -> syn::Result - { - let flags = Punctuated::::parse_terminated(input)?; - - for flag in &flags { - let name = flag.name().to_string(); - - if !FACTORY_MACRO_FLAGS.contains(&name.as_str()) { - return Err(input.error(format!( - "Unknown flag '{}'. Expected one of [ {} ]", - name, - FACTORY_MACRO_FLAGS.join(",") - ))); - } - } - - let flag_names = flags - .iter() - .map(|flag| flag.name().to_string()) - .collect::>(); - - if let Some((dupe_flag_name, _)) = flag_names.iter().find_duplicate() { - return Err(input.error(format!("Duplicate flag '{dupe_flag_name}'"))); - } - - Ok(Self { flags }) - } -} - -#[cfg(test)] -mod tests -{ - use proc_macro2::Span; - use quote::{format_ident, quote}; - use syn::{parse2, Lit, LitBool}; - - use super::*; - use crate::macro_flag::MacroFlagValue; - - #[test] - fn can_parse_with_single_flag() - { - let input_args = quote! { - threadsafe = true - }; - - let factory_macro_args = parse2::(input_args).unwrap(); - - assert_eq!( - factory_macro_args.flags, - Punctuated::from_iter(vec![MacroFlag { - name: format_ident!("threadsafe"), - value: MacroFlagValue::Literal(Lit::Bool(LitBool::new( - true, - Span::call_site() - ))) - }]) - ); - } - - #[test] - fn cannot_parse_with_invalid_flag() - { - let input_args = quote! { - threadsafe = false, foo = true - }; - - assert!(parse2::(input_args).is_err()); - } - - #[test] - fn cannot_parse_with_duplicate_flag() - { - assert!( - // Formatting is weird without this comment - parse2::(quote! { - threadsafe = true, threadsafe = true - }) - .is_err() - ); - - assert!( - // Formatting is weird without this comment - parse2::(quote! { - threadsafe = true, threadsafe = false - }) - .is_err() - ); - } -} diff --git a/macros/src/factory/mod.rs b/macros/src/factory/mod.rs deleted file mode 100644 index 18bad8f..0000000 --- a/macros/src/factory/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod build_declare_interfaces; -pub mod declare_default_args; -pub mod macro_args; -pub mod type_alias; diff --git a/macros/src/factory/type_alias.rs b/macros/src/factory/type_alias.rs deleted file mode 100644 index cfa254f..0000000 --- a/macros/src/factory/type_alias.rs +++ /dev/null @@ -1,68 +0,0 @@ -use quote::ToTokens; -use syn::parse::{Parse, ParseStream}; -use syn::{parse2, ItemType}; - -use crate::fn_trait::FnTrait; - -pub struct FactoryTypeAlias -{ - pub type_alias: ItemType, - pub factory_interface: FnTrait, -} - -impl Parse for FactoryTypeAlias -{ - fn parse(input: ParseStream) -> syn::Result - { - let type_alias = input - .parse::() - .map_err(|_| input.error("Expected a type alias"))?; - - let aliased_fn_trait = - parse2::(type_alias.ty.as_ref().to_token_stream())?; - - Ok(Self { - type_alias, - factory_interface: aliased_fn_trait.clone(), - }) - } -} - -#[cfg(test)] -mod tests -{ - use quote::{format_ident, quote}; - use syn::punctuated::Punctuated; - use syn::token::And; - use syn::{Type, TypeReference}; - - use super::*; - use crate::test_utils; - - #[test] - fn can_parse() - { - let input_args = quote! { - type FooFactory = dyn Fn(String, &u32) -> Foo; - }; - - let factory_type_alias = parse2::(input_args).unwrap(); - - assert_eq!( - factory_type_alias.factory_interface.inputs, - Punctuated::from_iter(vec![ - test_utils::create_type(test_utils::create_path(&[ - test_utils::create_path_segment(format_ident!("String"), &[]) - ])), - Type::Reference(TypeReference { - and_token: And::default(), - lifetime: None, - mutability: None, - elem: Box::new(test_utils::create_type(test_utils::create_path(&[ - test_utils::create_path_segment(format_ident!("u32"), &[]) - ]))) - }) - ]) - ); - } -} diff --git a/macros/src/fn_trait.rs b/macros/src/fn_trait.rs deleted file mode 100644 index 0858cca..0000000 --- a/macros/src/fn_trait.rs +++ /dev/null @@ -1,162 +0,0 @@ -use quote::ToTokens; -use syn::parse::Parse; -use syn::punctuated::Punctuated; -use syn::token::Paren; -use syn::{parenthesized, Ident, Token, TraitBound, Type}; - -/// A function trait. `dyn Fn(u32) -> String` -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FnTrait -{ - pub dyn_token: Token![dyn], - pub trait_ident: Ident, - pub paren_token: Paren, - pub inputs: Punctuated, - pub r_arrow_token: Token![->], - pub output: Type, - pub trait_bounds: Punctuated, -} - -impl FnTrait -{ - pub fn add_trait_bound(&mut self, trait_bound: TraitBound) - { - self.trait_bounds.push(trait_bound); - } -} - -impl Parse for FnTrait -{ - fn parse(input: syn::parse::ParseStream) -> syn::Result - { - let dyn_token = input.parse::()?; - - let trait_ident = input.parse::()?; - - if trait_ident.to_string().as_str() != "Fn" { - return Err(syn::Error::new(trait_ident.span(), "Expected 'Fn'")); - } - - let content; - - let paren_token = parenthesized!(content in input); - - let inputs = content.parse_terminated(Type::parse)?; - - let r_arrow_token = input.parse::]>()?; - - let output = input.parse::()?; - - Ok(Self { - dyn_token, - trait_ident, - paren_token, - inputs, - r_arrow_token, - output, - trait_bounds: Punctuated::new(), - }) - } -} - -impl ToTokens for FnTrait -{ - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) - { - self.dyn_token.to_tokens(tokens); - - self.trait_ident.to_tokens(tokens); - - self.paren_token.surround(tokens, |tokens_inner| { - self.inputs.to_tokens(tokens_inner); - }); - - self.r_arrow_token.to_tokens(tokens); - - self.output.to_tokens(tokens); - - if !self.trait_bounds.is_empty() { - let plus = ::default(); - - plus.to_tokens(tokens); - - self.trait_bounds.to_tokens(tokens); - } - } -} - -#[cfg(test)] -mod tests -{ - use quote::{format_ident, quote}; - use syn::token::{Dyn, RArrow}; - use syn::{parse2, PathSegment}; - - use super::*; - use crate::test_utils; - - #[test] - fn can_parse_fn_trait() - { - assert_eq!( - parse2::(quote! { - dyn Fn(String, u32) -> Handle - }) - .unwrap(), - FnTrait { - dyn_token: Dyn::default(), - trait_ident: format_ident!("Fn"), - paren_token: Paren::default(), - inputs: Punctuated::from_iter(vec![ - test_utils::create_type(test_utils::create_path(&[ - PathSegment::from(format_ident!("String")) - ])), - test_utils::create_type(test_utils::create_path(&[ - PathSegment::from(format_ident!("u32")) - ])) - ]), - r_arrow_token: RArrow::default(), - output: test_utils::create_type(test_utils::create_path(&[ - PathSegment::from(format_ident!("Handle")) - ])), - trait_bounds: Punctuated::new() - } - ); - - assert!(parse2::(quote! { - Fn(u32) -> Handle - }) - .is_err()); - } - - #[test] - fn can_parse_fn_trait_to_tokens() - { - assert_eq!( - FnTrait { - dyn_token: Dyn::default(), - trait_ident: format_ident!("Fn"), - paren_token: Paren::default(), - inputs: Punctuated::from_iter(vec![ - test_utils::create_type(test_utils::create_path(&[ - PathSegment::from(format_ident!("Bread")) - ])), - test_utils::create_type(test_utils::create_path(&[ - PathSegment::from(format_ident!("Cheese")) - ])), - test_utils::create_type(test_utils::create_path(&[ - PathSegment::from(format_ident!("Tomatoes")) - ])) - ]), - r_arrow_token: RArrow::default(), - output: test_utils::create_type(test_utils::create_path(&[ - PathSegment::from(format_ident!("Taco")) - ])), - trait_bounds: Punctuated::new() - } - .into_token_stream() - .to_string(), - "dyn Fn (Bread , Cheese , Tomatoes) -> Taco".to_string() - ); - } -} diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 7928e03..fa84e0e 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -35,12 +35,6 @@ mod injectable; mod macro_flag; mod util; -#[cfg(feature = "factory")] -mod factory; - -#[cfg(feature = "factory")] -mod fn_trait; - #[cfg(test)] mod test_utils; @@ -277,158 +271,6 @@ pub fn injectable(args_stream: TokenStream, input_stream: TokenStream) -> TokenS .into() } -/// Makes a type alias usable as a factory interface. -/// -/// # Arguments -/// * (Zero or more) Flags. Like `a = true, b = false` -/// -/// # Flags -/// - `threadsafe` - Mark as threadsafe. -/// -/// # Examples -/// ``` -/// # use syrette::factory; -/// # use syrette::ptr::TransientPtr; -/// # -/// # trait IConfigurator {} -/// # -/// # struct Configurator {} -/// # -/// # impl Configurator -/// # { -/// # fn new() -> Self -/// # { -/// # Self {} -/// # } -/// # } -/// # -/// # impl IConfigurator for Configurator {} -/// # -/// #[factory] -/// type IConfiguratorFactory = dyn Fn(Vec) -> TransientPtr; -/// ``` -/// -/// [`TransientPtr`]: https://docs.rs/syrette/latest/syrette/ptr/type.TransientPtr.html -#[cfg(feature = "factory")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))] -#[cfg(not(tarpaulin_include))] -#[proc_macro_error] -#[proc_macro_attribute] -pub fn factory(args_stream: TokenStream, input_stream: TokenStream) -> TokenStream -{ - use crate::factory::build_declare_interfaces::build_declare_factory_interfaces; - use crate::factory::macro_args::FactoryMacroArgs; - use crate::factory::type_alias::FactoryTypeAlias; - - set_dummy(input_stream.clone().into()); - - let FactoryMacroArgs { flags } = parse(args_stream).unwrap_or_abort(); - - let is_threadsafe = flags - .iter() - .find(|flag| flag.name() == "threadsafe") - .map_or(Ok(false), MacroFlag::get_bool) - .unwrap_or_abort(); - - let FactoryTypeAlias { - type_alias, - factory_interface, - } = parse(input_stream).unwrap_or_abort(); - - let decl_interfaces = - build_declare_factory_interfaces(&factory_interface, is_threadsafe); - - quote! { - #type_alias - - #decl_interfaces - } - .into() -} - -/// Shortcut for declaring a default factory. -/// -/// A default factory is a factory that doesn't take any arguments. -/// -/// Another way to accomplish what this macro does would be by using -/// the [`macro@factory`] macro. -/// -/// # Arguments -/// - Interface trait -/// * (Zero or more) Flags. Like `a = true, b = false` -/// -/// # Flags -/// - `threadsafe` - Mark as threadsafe. -/// - `async` - Mark as async. Infers the `threadsafe` flag. -/// -/// # Examples -/// ``` -/// # use syrette::declare_default_factory; -/// # -/// trait IParser -/// { -/// // Methods and etc here... -/// } -/// -/// declare_default_factory!(dyn IParser); -/// ``` -#[cfg(feature = "factory")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "factory")))] -#[cfg(not(tarpaulin_include))] -#[proc_macro_error] -#[proc_macro] -pub fn declare_default_factory(args_stream: TokenStream) -> TokenStream -{ - use syn::parse_str; - - use crate::factory::build_declare_interfaces::build_declare_factory_interfaces; - use crate::factory::declare_default_args::DeclareDefaultFactoryMacroArgs; - use crate::fn_trait::FnTrait; - - let DeclareDefaultFactoryMacroArgs { interface, flags } = - parse(args_stream).unwrap_or_abort(); - - let mut is_threadsafe = flags - .iter() - .find(|flag| flag.name() == "threadsafe") - .map_or(Ok(false), MacroFlag::get_bool) - .unwrap_or_abort(); - - let is_async = flags - .iter() - .find(|flag| flag.name() == "async") - .map_or(Ok(false), MacroFlag::get_bool) - .unwrap_or_abort(); - - if is_async { - is_threadsafe = true; - } - - let mut factory_interface: FnTrait = parse( - if is_async { - quote! { - dyn Fn() -> syrette::future::BoxFuture< - 'static, - syrette::ptr::TransientPtr<#interface> - > - } - } else { - quote! { - dyn Fn() -> syrette::ptr::TransientPtr<#interface> - } - } - .into(), - ) - .unwrap_or_abort(); - - if is_threadsafe { - factory_interface.add_trait_bound(parse_str("Send").unwrap_or_abort()); - factory_interface.add_trait_bound(parse_str("Sync").unwrap_or_abort()); - } - - build_declare_factory_interfaces(&factory_interface, is_threadsafe).into() -} - /// Declares the interface trait of a implementation. /// /// # Arguments -- cgit v1.2.3-18-g5258