aboutsummaryrefslogtreecommitdiff
path: root/macros/src
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2022-09-12 20:22:13 +0200
committerHampusM <hampus@hampusmat.com>2022-09-17 14:33:15 +0200
commitc1e682c25c24be3174d44ceb95b0537c38299d0c (patch)
tree6e59f37e1b98e68fad2e3e2fe4a428ac97fcf8b4 /macros/src
parente8e48906a3899e71c9c9d86a3d4528cb7d17e5b9 (diff)
feat!: allow factories access to DI container
BREAKING CHANGE: Factory types should now be written with the Fn trait instead of the IFactory trait and the to_factory & to_default_factory methods of BindingBuilder now expect a function returning a factory function
Diffstat (limited to 'macros/src')
-rw-r--r--macros/src/factory_type_alias.rs75
-rw-r--r--macros/src/fn_trait.rs68
-rw-r--r--macros/src/lib.rs26
3 files changed, 98 insertions, 71 deletions
diff --git a/macros/src/factory_type_alias.rs b/macros/src/factory_type_alias.rs
index 8ea7baa..64afe57 100644
--- a/macros/src/factory_type_alias.rs
+++ b/macros/src/factory_type_alias.rs
@@ -1,17 +1,20 @@
+use quote::ToTokens;
use syn::parse::{Parse, ParseStream};
-use syn::{GenericArgument, ItemType, Path, Type, TypeParamBound, TypeTuple};
+use syn::punctuated::Punctuated;
+use syn::{parse, ItemType, Token, Type};
+
+use crate::fn_trait::FnTrait;
pub struct FactoryTypeAlias
{
pub type_alias: ItemType,
- pub factory_interface: Path,
- pub arg_types: TypeTuple,
+ pub factory_interface: FnTrait,
+ pub arg_types: Punctuated<Type, Token![,]>,
pub return_type: Type,
}
impl Parse for FactoryTypeAlias
{
- #[allow(clippy::match_wildcard_for_single_variants)]
fn parse(input: ParseStream) -> syn::Result<Self>
{
let type_alias = match input.parse::<ItemType>() {
@@ -19,66 +22,14 @@ impl Parse for FactoryTypeAlias
Err(_) => Err(input.error("Expected a type alias")),
}?;
- let aliased_trait = match &type_alias.ty.as_ref() {
- Type::TraitObject(alias_type) => Ok(alias_type),
- &_ => Err(input.error("Expected the aliased type to be a trait")),
- }?;
-
- if aliased_trait.bounds.len() != 1 {
- return Err(input.error("Expected the aliased trait to have a single bound."));
- }
-
- let bound_path = &match aliased_trait.bounds.first().unwrap() {
- TypeParamBound::Trait(trait_bound) => Ok(trait_bound),
- &_ => {
- Err(input.error("Expected the bound of the aliased trait to be a trait"))
- }
- }?
- .path;
-
- if bound_path.segments.is_empty()
- || bound_path.segments.last().unwrap().ident != "IFactory"
- {
- return Err(input
- .error("Expected the bound of the aliased trait to be 'dyn IFactory'"));
- }
-
- let angle_bracketed_args = match &bound_path.segments.last().unwrap().arguments {
- syn::PathArguments::AngleBracketed(angle_bracketed_args) => {
- Ok(angle_bracketed_args)
- }
- &_ => {
- Err(input.error("Expected angle bracketed arguments for 'dyn IFactory'"))
- }
- }?;
-
- let arg_types = match &angle_bracketed_args.args[0] {
- GenericArgument::Type(arg_types_type) => match arg_types_type {
- Type::Tuple(arg_types) => Ok(arg_types),
- &_ => Err(input.error(concat!(
- "Expected the first angle bracketed argument ",
- "of 'dyn IFactory' to be a type tuple"
- ))),
- },
- &_ => Err(input.error(concat!(
- "Expected the first angle bracketed argument ",
- "of 'dyn IFactory' to be a type"
- ))),
- }?;
-
- let return_type = match &angle_bracketed_args.args[1] {
- GenericArgument::Type(arg_type) => Ok(arg_type),
- &_ => Err(input.error(concat!(
- "Expected the second angle bracketed argument ",
- "of 'dyn IFactory' to be a type"
- ))),
- }?;
+ let aliased_fn_trait =
+ parse::<FnTrait>(type_alias.ty.as_ref().to_token_stream().into())?;
Ok(Self {
- type_alias: type_alias.clone(),
- factory_interface: bound_path.clone(),
- arg_types: arg_types.clone(),
- return_type: return_type.clone(),
+ type_alias,
+ factory_interface: aliased_fn_trait.clone(),
+ arg_types: aliased_fn_trait.inputs,
+ return_type: aliased_fn_trait.output,
})
}
}
diff --git a/macros/src/fn_trait.rs b/macros/src/fn_trait.rs
new file mode 100644
index 0000000..f9b3514
--- /dev/null
+++ b/macros/src/fn_trait.rs
@@ -0,0 +1,68 @@
+use quote::ToTokens;
+use syn::parse::Parse;
+use syn::punctuated::Punctuated;
+use syn::token::Paren;
+use syn::{parenthesized, Ident, Token, Type};
+
+/// A function trait. `dyn Fn(u32) -> String`
+#[derive(Debug, Clone)]
+pub struct FnTrait
+{
+ pub dyn_token: Token![dyn],
+ pub trait_ident: Ident,
+ pub paren_token: Paren,
+ pub inputs: Punctuated<Type, Token![,]>,
+ pub r_arrow_token: Token![->],
+ pub output: Type,
+}
+
+impl Parse for FnTrait
+{
+ fn parse(input: syn::parse::ParseStream) -> syn::Result<Self>
+ {
+ let dyn_token = input.parse::<Token![dyn]>()?;
+
+ let trait_ident = input.parse::<Ident>()?;
+
+ 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::<Token![->]>()?;
+
+ let output = input.parse::<Type>()?;
+
+ Ok(Self {
+ dyn_token,
+ trait_ident,
+ paren_token,
+ inputs,
+ r_arrow_token,
+ output,
+ })
+ }
+}
+
+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);
+ }
+}
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index 25f3c5c..4c815db 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -13,6 +13,7 @@ mod declare_interface_args;
mod dependency;
mod factory_macro_args;
mod factory_type_alias;
+mod fn_trait;
mod injectable_impl;
mod injectable_macro_args;
mod libs;
@@ -166,6 +167,7 @@ pub fn injectable(args_stream: TokenStream, impl_stream: TokenStream) -> TokenSt
/// ```
/// # use syrette::factory;
/// # use syrette::interfaces::factory::IFactory;
+/// # use syrette::ptr::TransientPtr;
/// #
/// # trait IConfigurator {}
/// #
@@ -182,7 +184,7 @@ pub fn injectable(args_stream: TokenStream, impl_stream: TokenStream) -> TokenSt
/// # impl IConfigurator for Configurator {}
/// #
/// #[factory]
-/// type IConfiguratorFactory = dyn IFactory<(Vec<String>,), dyn IConfigurator>;
+/// type IConfiguratorFactory = dyn Fn(Vec<String>) -> TransientPtr<dyn IConfigurator>;
/// ```
#[proc_macro_attribute]
#[cfg(feature = "factory")]
@@ -226,15 +228,18 @@ pub fn factory(args_stream: TokenStream, type_alias_stream: TokenStream) -> Toke
quote! {
syrette::declare_interface!(
syrette::castable_factory::blocking::CastableFactory<
- #arg_types,
- #return_type
- > -> #factory_interface
+ (std::rc::Rc<syrette::di_container::DIContainer>,),
+ #factory_interface
+ > -> syrette::interfaces::factory::IFactory<
+ (std::rc::Rc<syrette::di_container::DIContainer>,),
+ #factory_interface
+ >
);
syrette::declare_interface!(
syrette::castable_factory::blocking::CastableFactory<
- #arg_types,
- #return_type
+ (std::rc::Rc<syrette::di_container::DIContainer>,),
+ #factory_interface
> -> syrette::interfaces::any_factory::AnyFactory
);
}
@@ -315,14 +320,17 @@ pub fn declare_default_factory(args_stream: TokenStream) -> TokenStream
quote! {
syrette::declare_interface!(
syrette::castable_factory::blocking::CastableFactory<
- (),
+ (std::rc::Rc<syrette::di_container::DIContainer>,),
#interface,
- > -> syrette::interfaces::factory::IFactory<(), #interface>
+ > -> syrette::interfaces::factory::IFactory<
+ (std::rc::Rc<syrette::di_container::DIContainer>,),
+ #interface
+ >
);
syrette::declare_interface!(
syrette::castable_factory::blocking::CastableFactory<
- (),
+ (std::rc::Rc<syrette::di_container::DIContainer>,),
#interface,
> -> syrette::interfaces::any_factory::AnyFactory
);