From f75a7d58135825c4f9094c1e10f36de4a952f455 Mon Sep 17 00:00:00 2001 From: HampusM Date: Wed, 27 Jul 2022 19:10:30 +0200 Subject: feat: add injecting singletons into constructors --- macros/src/dependency_type.rs | 40 ++++++++++++++++++++++ macros/src/injectable_impl.rs | 79 ++++++++++++++++++------------------------- macros/src/lib.rs | 1 + 3 files changed, 74 insertions(+), 46 deletions(-) create mode 100644 macros/src/dependency_type.rs (limited to 'macros/src') diff --git a/macros/src/dependency_type.rs b/macros/src/dependency_type.rs new file mode 100644 index 0000000..35f810e --- /dev/null +++ b/macros/src/dependency_type.rs @@ -0,0 +1,40 @@ +use proc_macro2::Ident; +use syn::{GenericArgument, PathArguments, Type, TypePath}; + +pub struct DependencyType +{ + pub interface: Type, + pub ptr: Ident, +} + +impl DependencyType +{ + pub fn from_type_path(type_path: &TypePath) -> Option + { + // Assume the type path has a last segment. + let last_path_segment = type_path.path.segments.last().unwrap(); + + let ptr = &last_path_segment.ident; + + 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 TransientPtr, + // SingletonPtr 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(Self { + interface: first_generic_arg_type.clone(), + ptr: ptr.clone(), + }), + &_ => None, + } + } + &_ => None, + } + } +} diff --git a/macros/src/injectable_impl.rs b/macros/src/injectable_impl.rs index 89346e8..f510407 100644 --- a/macros/src/injectable_impl.rs +++ b/macros/src/injectable_impl.rs @@ -2,16 +2,17 @@ use quote::{quote, ToTokens}; use syn::parse::{Parse, ParseStream}; use syn::Generics; use syn::{ - parse_str, punctuated::Punctuated, token::Comma, ExprMethodCall, FnArg, - GenericArgument, Ident, ImplItem, ImplItemMethod, ItemImpl, Path, PathArguments, - Type, TypePath, + parse_str, punctuated::Punctuated, token::Comma, ExprMethodCall, FnArg, Ident, + ImplItem, ImplItemMethod, ItemImpl, Path, Type, TypePath, }; +use crate::dependency_type::DependencyType; + const DI_CONTAINER_VAR_NAME: &str = "di_container"; pub struct InjectableImpl { - pub dependency_types: Vec, + pub dependency_types: Vec, pub self_type: Type, pub generics: Generics, pub original_impl: ItemImpl, @@ -21,20 +22,17 @@ impl Parse for InjectableImpl { fn parse(input: ParseStream) -> syn::Result { - match input.parse::() { - 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(), - generics: impl_parsed_input.generics.clone(), - original_impl: impl_parsed_input, - }), - Err(error_msg) => Err(input.error(error_msg)), - } - } - Err(_) => Err(input.error("Expected an impl")), - } + let impl_parsed_input = input.parse::()?; + + let dependency_types = Self::_get_dependency_types(&impl_parsed_input) + .map_err(|err| input.error(err))?; + + Ok(Self { + dependency_types, + self_type: impl_parsed_input.self_ty.as_ref().clone(), + generics: impl_parsed_input.generics.clone(), + original_impl: impl_parsed_input, + }) } } @@ -81,16 +79,23 @@ impl InjectableImpl } } - fn _create_get_dependencies(dependency_types: &[Type]) -> Vec + fn _create_get_dependencies( + dependency_types: &[DependencyType], + ) -> Vec { dependency_types .iter() - .filter_map(|dep_type| match dep_type { + .filter_map(|dep_type| match &dep_type.interface { Type::TraitObject(dep_type_trait) => Some( parse_str( format!( - "{}.get::<{}>()", + "{}.get{}::<{}>()", DI_CONTAINER_VAR_NAME, + if dep_type.ptr == "SingletonPtr" { + "_singleton" + } else { + "" + }, dep_type_trait.to_token_stream() ) .as_str(), @@ -194,12 +199,17 @@ impl InjectableImpl arg_type_path_string == "TransientPtr" || arg_type_path_string == "ptr::TransientPtr" || arg_type_path_string == "syrrete::ptr::TransientPtr" + || arg_type_path_string == "SingletonPtr" + || arg_type_path_string == "ptr::SingletonPtr" + || arg_type_path_string == "syrrete::ptr::SingletonPtr" || 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, &'static str> + fn _get_dependency_types( + item_impl: &ItemImpl, + ) -> Result, &'static str> { let new_method_impl_item = match Self::_find_method_by_name(item_impl, "new") { Some(method_item) => Ok(method_item), @@ -223,30 +233,7 @@ impl InjectableImpl 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 TransientPtr 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, - } - }) + .filter_map(|arg_type_path| DependencyType::from_type_path(arg_type_path)) .collect()) } } diff --git a/macros/src/lib.rs b/macros/src/lib.rs index d65df68..20eb7d3 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -6,6 +6,7 @@ use quote::quote; use syn::{parse, parse_macro_input}; mod declare_interface_args; +mod dependency_type; mod factory_type_alias; mod injectable_impl; mod injectable_macro_args; -- cgit v1.2.3-18-g5258