aboutsummaryrefslogtreecommitdiff
path: root/syrette_macros
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2022-07-17 14:55:41 +0200
committerHampusM <hampus@hampusmat.com>2022-07-17 14:55:41 +0200
commit51e8d04c2299e6468213d8ee4f9e15d783094379 (patch)
tree77dd9436588a1fc8a15fbf7e8da7b8e7068bd0b1 /syrette_macros
parente906a0fc5922776b8ecd17e3100b24fc44cedf19 (diff)
refactor: reorganize and improve macros
Diffstat (limited to 'syrette_macros')
-rw-r--r--syrette_macros/src/factory_type_alias.rs83
-rw-r--r--syrette_macros/src/injectable_impl.rs244
-rw-r--r--syrette_macros/src/injectable_macro_args.rs17
-rw-r--r--syrette_macros/src/lib.rs385
4 files changed, 430 insertions, 299 deletions
diff --git a/syrette_macros/src/factory_type_alias.rs b/syrette_macros/src/factory_type_alias.rs
new file mode 100644
index 0000000..82e2315
--- /dev/null
+++ b/syrette_macros/src/factory_type_alias.rs
@@ -0,0 +1,83 @@
+use syn::parse::{Parse, ParseStream};
+use syn::{GenericArgument, ItemType, Path, Type, TypeParamBound, TypeTuple};
+
+pub struct FactoryTypeAlias
+{
+ pub type_alias: ItemType,
+ pub factory_interface: Path,
+ pub arg_types: TypeTuple,
+ pub return_type: Type,
+}
+
+impl Parse for FactoryTypeAlias
+{
+ fn parse(input: ParseStream) -> syn::Result<Self>
+ {
+ let type_alias = match input.parse::<ItemType>() {
+ Ok(type_alias) => Ok(type_alias),
+ 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"
+ ))),
+ }?;
+
+ Ok(Self {
+ type_alias: type_alias.clone(),
+ factory_interface: bound_path.clone(),
+ arg_types: arg_types.clone(),
+ return_type: return_type.clone(),
+ })
+ }
+}
diff --git a/syrette_macros/src/injectable_impl.rs b/syrette_macros/src/injectable_impl.rs
new file mode 100644
index 0000000..e7d1b54
--- /dev/null
+++ b/syrette_macros/src/injectable_impl.rs
@@ -0,0 +1,244 @@
+use quote::{quote, ToTokens};
+use syn::parse::{Parse, ParseStream};
+use syn::{
+ parse_str, punctuated::Punctuated, token::Comma, ExprMethodCall, FnArg,
+ GenericArgument, Ident, ImplItem, ImplItemMethod, ItemImpl, Path, PathArguments,
+ Type, TypePath,
+};
+
+const DI_CONTAINER_VAR_NAME: &str = "di_container";
+
+pub struct InjectableImpl
+{
+ pub dependency_types: Vec<Type>,
+ pub self_type: Type,
+ pub original_impl: ItemImpl,
+}
+
+impl Parse for InjectableImpl
+{
+ fn parse(input: ParseStream) -> syn::Result<Self>
+ {
+ match input.parse::<ItemImpl>() {
+ Ok(impl_parsed_input) => {
+ match Self::_get_dependency_types(&impl_parsed_input) {
+ Ok(dependency_types) => Ok(Self {
+ dependency_types,
+ self_type: impl_parsed_input.self_ty.as_ref().clone(),
+ original_impl: impl_parsed_input,
+ }),
+ Err(error_msg) => Err(input.error(error_msg)),
+ }
+ }
+ Err(_) => Err(input.error("Expected an impl")),
+ }
+ }
+}
+
+impl InjectableImpl
+{
+ pub fn expand(&self) -> proc_macro2::TokenStream
+ {
+ let original_impl = &self.original_impl;
+ let self_type = &self.self_type;
+
+ let di_container_var: Ident = parse_str(DI_CONTAINER_VAR_NAME).unwrap();
+
+ let get_dependencies = Self::_create_get_dependencies(&self.dependency_types);
+
+ quote! {
+ #original_impl
+
+ impl syrette::interfaces::injectable::Injectable for #self_type {
+ fn resolve(
+ #di_container_var: &syrette::DIContainer
+ ) -> error_stack::Result<
+ syrette::ptr::InterfacePtr<Self>,
+ syrette::errors::injectable::ResolveError>
+ {
+ use error_stack::ResultExt;
+
+ return Ok(syrette::ptr::InterfacePtr::new(Self::new(
+ #(#get_dependencies
+ .change_context(syrette::errors::injectable::ResolveError)
+ .attach_printable(
+ format!(
+ "Unable to resolve a dependency of {}",
+ std::any::type_name::<#self_type>()
+ )
+ )?
+ ),*
+ )));
+ }
+ }
+ }
+ }
+
+ fn _create_get_dependencies(dependency_types: &[Type]) -> Vec<ExprMethodCall>
+ {
+ dependency_types
+ .iter()
+ .filter_map(|dep_type| match dep_type {
+ Type::TraitObject(dep_type_trait) => Some(
+ parse_str(
+ format!(
+ "{}.get::<{}>()",
+ DI_CONTAINER_VAR_NAME,
+ dep_type_trait.to_token_stream()
+ )
+ .as_str(),
+ )
+ .unwrap(),
+ ),
+ Type::Path(dep_type_path) => {
+ let dep_type_path_str = Self::_path_to_string(&dep_type_path.path);
+
+ let get_method_name = if dep_type_path_str.ends_with("Factory") {
+ "get_factory"
+ } else {
+ "get"
+ };
+
+ Some(
+ parse_str(
+ format!(
+ "{}.{}::<{}>()",
+ DI_CONTAINER_VAR_NAME, get_method_name, dep_type_path_str
+ )
+ .as_str(),
+ )
+ .unwrap(),
+ )
+ }
+ &_ => None,
+ })
+ .collect()
+ }
+
+ fn _find_method_by_name<'impl_lt>(
+ item_impl: &'impl_lt ItemImpl,
+ method_name: &'static str,
+ ) -> Option<&'impl_lt ImplItemMethod>
+ {
+ let impl_items = &item_impl.items;
+
+ impl_items
+ .iter()
+ .filter_map(|impl_item| match impl_item {
+ ImplItem::Method(method_item) => Some(method_item),
+ &_ => None,
+ })
+ .find(|method_item| method_item.sig.ident == method_name)
+ }
+
+ fn get_has_fn_args_self(fn_args: &Punctuated<FnArg, Comma>) -> bool
+ {
+ fn_args.iter().any(|arg| match arg {
+ FnArg::Receiver(_) => true,
+ &_ => false,
+ })
+ }
+
+ fn _get_fn_arg_type_paths(fn_args: &Punctuated<FnArg, Comma>) -> Vec<&TypePath>
+ {
+ fn_args
+ .iter()
+ .filter_map(|arg| match arg {
+ FnArg::Typed(typed_fn_arg) => match typed_fn_arg.ty.as_ref() {
+ Type::Path(arg_type_path) => Some(arg_type_path),
+ Type::Reference(ref_type_path) => match ref_type_path.elem.as_ref() {
+ Type::Path(arg_type_path) => Some(arg_type_path),
+ &_ => None,
+ },
+ &_ => None,
+ },
+ FnArg::Receiver(_receiver_fn_arg) => None,
+ })
+ .collect()
+ }
+
+ fn _path_to_string(path: &Path) -> String
+ {
+ path.segments
+ .pairs()
+ .fold(String::new(), |mut acc, segment_pair| {
+ let segment_ident = &segment_pair.value().ident;
+
+ acc.push_str(segment_ident.to_string().as_str());
+
+ let opt_colon_two = segment_pair.punct();
+
+ match opt_colon_two {
+ Some(colon_two) => {
+ acc.push_str(colon_two.to_token_stream().to_string().as_str())
+ }
+ None => {}
+ }
+
+ acc
+ })
+ }
+
+ fn _is_type_path_ptr(type_path: &TypePath) -> bool
+ {
+ let arg_type_path_string = Self::_path_to_string(&type_path.path);
+
+ arg_type_path_string == "InterfacePtr"
+ || arg_type_path_string == "ptr::InterfacePtr"
+ || arg_type_path_string == "syrrete::ptr::InterfacePtr"
+ || arg_type_path_string == "FactoryPtr"
+ || arg_type_path_string == "ptr::FactoryPtr"
+ || arg_type_path_string == "syrrete::ptr::FactoryPtr"
+ }
+
+ fn _get_dependency_types(item_impl: &ItemImpl) -> Result<Vec<Type>, &'static str>
+ {
+ let new_method_impl_item = match Self::_find_method_by_name(item_impl, "new") {
+ Some(method_item) => Ok(method_item),
+ None => Err("Missing a 'new' method"),
+ }?;
+
+ let new_method_args = &new_method_impl_item.sig.inputs;
+
+ if Self::get_has_fn_args_self(new_method_args) {
+ return Err("Unexpected self argument in 'new' method");
+ }
+
+ let new_method_arg_type_paths = Self::_get_fn_arg_type_paths(new_method_args);
+
+ if new_method_arg_type_paths
+ .iter()
+ .any(|arg_type_path| !Self::_is_type_path_ptr(arg_type_path))
+ {
+ return Err("All argument types in 'new' method must ptr types");
+ }
+
+ Ok(new_method_arg_type_paths
+ .iter()
+ .filter_map(|arg_type_path| {
+ // Assume the type path has a last segment.
+ let last_path_segment = arg_type_path.path.segments.last().unwrap();
+
+ match &last_path_segment.arguments {
+ PathArguments::AngleBracketed(angle_bracketed_generic_args) => {
+ let generic_args = &angle_bracketed_generic_args.args;
+
+ let opt_first_generic_arg = generic_args.first();
+
+ // Assume a first generic argument exists because InterfacePtr and
+ // FactoryPtr requires one
+ let first_generic_arg = opt_first_generic_arg.as_ref().unwrap();
+
+ match first_generic_arg {
+ GenericArgument::Type(first_generic_arg_type) => {
+ Some(first_generic_arg_type.clone())
+ }
+ &_ => None,
+ }
+ }
+ &_ => None,
+ }
+ })
+ .collect())
+ }
+}
diff --git a/syrette_macros/src/injectable_macro_args.rs b/syrette_macros/src/injectable_macro_args.rs
new file mode 100644
index 0000000..4ef4389
--- /dev/null
+++ b/syrette_macros/src/injectable_macro_args.rs
@@ -0,0 +1,17 @@
+use syn::parse::{Parse, ParseStream};
+use syn::TypePath;
+
+pub struct InjectableMacroArgs
+{
+ pub interface: TypePath,
+}
+
+impl Parse for InjectableMacroArgs
+{
+ fn parse(input: ParseStream) -> syn::Result<Self>
+ {
+ Ok(Self {
+ interface: input.parse()?,
+ })
+ }
+}
diff --git a/syrette_macros/src/lib.rs b/syrette_macros/src/lib.rs
index 91a0562..3145b5f 100644
--- a/syrette_macros/src/lib.rs
+++ b/syrette_macros/src/lib.rs
@@ -1,162 +1,21 @@
use proc_macro::TokenStream;
-use quote::{quote, ToTokens};
-use syn::{
- parse, parse_macro_input, parse_str, punctuated::Punctuated, token::Comma,
- AttributeArgs, ExprMethodCall, FnArg, GenericArgument, ImplItem, ItemImpl, ItemType,
- Meta, NestedMeta, Path, PathArguments, Type, TypeParamBound, TypePath,
-};
+use quote::quote;
+use syn::{parse, parse_macro_input};
+mod factory_type_alias;
+mod injectable_impl;
+mod injectable_macro_args;
mod libs;
+use factory_type_alias::FactoryTypeAlias;
+use injectable_impl::InjectableImpl;
+use injectable_macro_args::InjectableMacroArgs;
use libs::intertrait_macros::{
args::{Casts, Flag, Targets},
gen_caster::generate_caster,
};
-const NO_INTERFACE_ARG_ERR_MESSAGE: &str =
- "Expected a argument specifying a interface trait";
-
-const INVALID_ARG_ERR_MESSAGE: &str = "Invalid argument passed";
-
-const INVALID_ITEM_TYPE_ERR_MESSAGE: &str =
- "The attached to item is not a trait implementation";
-
-const IMPL_NO_NEW_METHOD_ERR_MESSAGE: &str =
- "The attached to trait implementation is missing a new method";
-
-const IMPL_NEW_METHOD_SELF_PARAM_ERR_MESSAGE: &str =
- "The new method of the attached to trait implementation cannot have a self parameter";
-
-const IMPL_NEW_METHOD_PARAM_TYPES_ERR_MESSAGE: &str = concat!(
- "All parameters of the new method of the attached to trait implementation ",
- "must be either syrette::ptr::InterfacePtr or syrrete::ptr::FactoryPtr (for factories)"
-);
-
-const INVALID_ALIASED_FACTORY_TRAIT_ERR_MESSAGE: &str =
- "Invalid aliased trait. Must be 'dyn IFactory'";
-
-const INVALID_ALIASED_FACTORY_ARGS_ERR_MESSAGE: &str =
- "Invalid arguments for 'dyn IFactory'";
-
-fn path_to_string(path: &Path) -> String
-{
- return path
- .segments
- .pairs()
- .fold(String::new(), |mut acc, segment_pair| {
- let segment_ident = &segment_pair.value().ident;
-
- acc.push_str(segment_ident.to_string().as_str());
-
- let opt_colon_two = segment_pair.punct();
-
- match opt_colon_two {
- Some(colon_two) => {
- acc.push_str(colon_two.to_token_stream().to_string().as_str())
- }
- None => {}
- }
-
- acc
- });
-}
-
-fn get_fn_args_has_self(fn_args: &Punctuated<FnArg, Comma>) -> bool
-{
- return fn_args.iter().any(|arg| match arg {
- FnArg::Receiver(_) => true,
- &_ => false,
- });
-}
-
-fn get_fn_arg_type_paths(fn_args: &Punctuated<FnArg, Comma>) -> Vec<TypePath>
-{
- return fn_args.iter().fold(Vec::<TypePath>::new(), |mut acc, arg| {
- match arg {
- FnArg::Typed(typed_fn_arg) => match typed_fn_arg.ty.as_ref() {
- Type::Path(arg_type_path) => acc.push(arg_type_path.clone()),
- Type::Reference(ref_type_path) => match ref_type_path.elem.as_ref() {
- Type::Path(arg_type_path) => acc.push(arg_type_path.clone()),
- &_ => {}
- },
- &_ => {}
- },
- FnArg::Receiver(_receiver_fn_arg) => {}
- }
-
- acc
- });
-}
-
-fn get_dependency_types(item_impl: &ItemImpl) -> Vec<Type>
-{
- let impl_items = &item_impl.items;
-
- let opt_new_method_impl_item = impl_items.iter().find(|item| match item {
- ImplItem::Method(method_item) => method_item.sig.ident == "new",
- &_ => false,
- });
-
- let new_method_impl_item = match opt_new_method_impl_item {
- Some(item) => match item {
- ImplItem::Method(method_item) => method_item,
- &_ => panic!("{}", IMPL_NO_NEW_METHOD_ERR_MESSAGE),
- },
- None => panic!("{}", IMPL_NO_NEW_METHOD_ERR_MESSAGE),
- };
-
- let new_method_inputs = &new_method_impl_item.sig.inputs;
-
- if get_fn_args_has_self(new_method_inputs) {
- panic!("{}", IMPL_NEW_METHOD_SELF_PARAM_ERR_MESSAGE)
- }
-
- let new_method_arg_type_paths = get_fn_arg_type_paths(new_method_inputs);
-
- return new_method_arg_type_paths.iter().fold(
- Vec::<Type>::new(),
- |mut acc, arg_type_path| {
- let arg_type_path_string = path_to_string(&arg_type_path.path);
-
- if arg_type_path_string != "InterfacePtr"
- && arg_type_path_string != "ptr::InterfacePtr"
- && arg_type_path_string != "syrrete::ptr::InterfacePtr"
- && arg_type_path_string != "FactoryPtr"
- && arg_type_path_string != "ptr::FactoryPtr"
- && arg_type_path_string != "syrrete::ptr::FactoryPtr"
- {
- panic!("{}", IMPL_NEW_METHOD_PARAM_TYPES_ERR_MESSAGE);
- }
-
- // Assume the type path has a last segment.
- let last_path_segment = arg_type_path.path.segments.last().unwrap();
-
- match &last_path_segment.arguments {
- PathArguments::AngleBracketed(angle_bracketed_generic_args) => {
- let generic_args = &angle_bracketed_generic_args.args;
-
- let opt_first_generic_arg = generic_args.first();
-
- // Assume a first generic argument exists because InterfacePtr and
- // FactoryPtr requires one
- let first_generic_arg = opt_first_generic_arg.as_ref().unwrap();
-
- match first_generic_arg {
- GenericArgument::Type(first_generic_arg_type) => {
- acc.push(first_generic_arg_type.clone());
- }
- &_ => {}
- }
- }
- &_ => {}
- }
-
- acc
- },
- );
-}
-
-/// Makes a struct injectable. Therefore usable with `DIContainer`.
+/// Makes a struct injectable. Thereby usable with `DIContainer`.
///
/// # Arguments
///
@@ -166,15 +25,28 @@ fn get_dependency_types(item_impl: &ItemImpl) -> Vec<Type>
/// ```
/// trait IConfigReader
/// {
-/// fn read_config() -> Config;
+/// fn read_config(&self) -> Config;
+/// }
+///
+/// struct ConfigReader
+/// {
+/// _file_reader: InterfacePtr<IFileReader>,
/// }
///
-/// struct ConfigReader {}
+/// impl ConfigReader
+/// {
+/// fn new(file_reader: InterfacePtr<IFileReader>) -> Self
+/// {
+/// Self {
+/// _file_reader: file_reader
+/// }
+/// }
+/// }
///
/// #[injectable(IConfigReader)]
/// impl IConfigReader for ConfigReader
/// {
-/// fn read_config() -> Config
+/// fn read_config(&self) -> Config
/// {
/// // Stuff here
/// }
@@ -183,175 +55,90 @@ fn get_dependency_types(item_impl: &ItemImpl) -> Vec<Type>
#[proc_macro_attribute]
pub fn injectable(args_stream: TokenStream, impl_stream: TokenStream) -> TokenStream
{
- let args = parse_macro_input!(args_stream as AttributeArgs);
+ let InjectableMacroArgs {
+ interface: interface_type_path,
+ } = parse_macro_input!(args_stream);
- if args.is_empty() {
- panic!("{}", NO_INTERFACE_ARG_ERR_MESSAGE);
- }
+ let injectable_impl: InjectableImpl = parse(impl_stream).unwrap();
- if args.len() > 1 {
- panic!("Only a single argument is expected");
- }
-
- let interface_path = match &args[0] {
- NestedMeta::Meta(arg_meta) => match arg_meta {
- Meta::Path(path_arg) => path_arg,
- &_ => panic!("{}", INVALID_ARG_ERR_MESSAGE),
- },
- &_ => panic!("{}", INVALID_ARG_ERR_MESSAGE),
- };
-
- let item_impl: ItemImpl = match parse(impl_stream) {
- Ok(impl_parsed) => impl_parsed,
- Err(_) => {
- panic!("{}", INVALID_ITEM_TYPE_ERR_MESSAGE)
- }
- };
-
- let self_type = item_impl.self_ty.as_ref();
-
- let self_type_path = match self_type {
- Type::Path(path_self_type) => path_self_type.path.clone(),
- &_ => parse_str("invalid_type").unwrap(),
- };
-
- let dependency_types = get_dependency_types(&item_impl);
+ let expanded_injectable_impl = injectable_impl.expand();
- let get_dependencies = dependency_types.iter().fold(
- Vec::<ExprMethodCall>::new(),
- |mut acc, dep_type| {
- match dep_type {
- Type::TraitObject(dep_type_trait) => {
- acc.push(
- parse_str(
- format!(
- "di_container.get::<{}>()",
- dep_type_trait.to_token_stream()
- )
- .as_str(),
- )
- .unwrap(),
- );
- }
- Type::Path(dep_type_path) => {
- let dep_type_path_str = path_to_string(&dep_type_path.path);
-
- let get_method_name = if dep_type_path_str.ends_with("Factory") {
- "get_factory"
- } else {
- "get"
- };
-
- acc.push(
- parse_str(
- format!(
- "di_container.{}::<{}>()",
- get_method_name, dep_type_path_str
- )
- .as_str(),
- )
- .unwrap(),
- );
- }
- &_ => {}
- }
-
- acc
- },
- );
+ let self_type = &injectable_impl.self_type;
quote! {
- #item_impl
+ #expanded_injectable_impl
- impl syrette::interfaces::injectable::Injectable for #self_type_path {
- fn resolve(
- di_container: &syrette::DIContainer
- ) -> error_stack::Result<
- syrette::ptr::InterfacePtr<Self>,
- syrette::errors::injectable::ResolveError>
- {
- use error_stack::ResultExt;
-
- return Ok(syrette::ptr::InterfacePtr::new(Self::new(
- #(#get_dependencies
- .change_context(syrette::errors::injectable::ResolveError)
- .attach_printable(
- format!(
- "Unable to resolve a dependency of {}",
- std::any::type_name::<#self_type_path>()
- )
- )?
- ),*
- )));
- }
- }
-
- syrette::castable_to!(#self_type_path => #interface_path);
+ syrette::castable_to!(#self_type => #interface_type_path);
}
.into()
}
+/// Makes a type alias usable as a factory interface.
+///
+/// # Examples
+/// ```
+/// trait IUser
+/// {
+/// fn name(&self) -> String;
+/// fn age(&self) -> i32;
+/// }
+///
+/// struct User
+/// {
+/// _name: String,
+/// _age: i32,
+/// }
+///
+/// impl User
+/// {
+/// fn new(name: String, age: i32) -> Self
+/// {
+/// Self {
+/// _name: name,
+/// _age: age,
+/// }
+/// }
+/// }
+///
+/// impl IUser for User
+/// {
+/// fn name(&self) -> String
+/// {
+/// self._name
+/// }
+///
+/// fn age(&self) -> i32
+/// {
+/// self._age
+/// }
+/// }
+///
+/// type UserFactory = dyn IFactory<(String, i32), dyn IUser>;
+/// ```
#[proc_macro_attribute]
pub fn factory(_: TokenStream, type_alias_stream: TokenStream) -> TokenStream
{
- let type_alias: ItemType = parse(type_alias_stream).unwrap();
-
- let aliased_trait = match &type_alias.ty.as_ref() {
- Type::TraitObject(alias_type) => alias_type,
- &_ => panic!("{}", INVALID_ALIASED_FACTORY_TRAIT_ERR_MESSAGE),
- };
-
- if aliased_trait.bounds.len() != 1 {
- panic!("{}", INVALID_ALIASED_FACTORY_TRAIT_ERR_MESSAGE);
- }
-
- let type_bound = aliased_trait.bounds.first().unwrap();
-
- let trait_bound = match type_bound {
- TypeParamBound::Trait(trait_bound) => trait_bound,
- &_ => panic!("{}", INVALID_ALIASED_FACTORY_TRAIT_ERR_MESSAGE),
- };
-
- let trait_bound_path = &trait_bound.path;
-
- if trait_bound_path.segments.is_empty()
- || trait_bound_path.segments.last().unwrap().ident != "IFactory"
- {
- panic!("{}", INVALID_ALIASED_FACTORY_TRAIT_ERR_MESSAGE);
- }
-
- let factory_path_segment = trait_bound_path.segments.last().unwrap();
-
- let factory_path_segment_args = &match &factory_path_segment.arguments {
- syn::PathArguments::AngleBracketed(args) => args,
- &_ => panic!("{}", INVALID_ALIASED_FACTORY_ARGS_ERR_MESSAGE),
- }
- .args;
-
- let factory_arg_types_type = match &factory_path_segment_args[0] {
- GenericArgument::Type(arg_type) => arg_type,
- &_ => panic!("{}", INVALID_ALIASED_FACTORY_ARGS_ERR_MESSAGE),
- };
-
- let factory_return_type = match &factory_path_segment_args[1] {
- GenericArgument::Type(arg_type) => arg_type,
- &_ => panic!("{}", INVALID_ALIASED_FACTORY_ARGS_ERR_MESSAGE),
- };
+ let FactoryTypeAlias {
+ type_alias,
+ factory_interface,
+ arg_types,
+ return_type,
+ } = parse(type_alias_stream).unwrap();
quote! {
#type_alias
syrette::castable_to!(
syrette::castable_factory::CastableFactory<
- #factory_arg_types_type,
- #factory_return_type
- > => #trait_bound_path
+ #arg_types,
+ #return_type
+ > => #factory_interface
);
syrette::castable_to!(
syrette::castable_factory::CastableFactory<
- #factory_arg_types_type,
- #factory_return_type
+ #arg_types,
+ #return_type
> => syrette::castable_factory::AnyFactory
);
}