From e0f90a8e384615c79d7d51c66d19294d75e79391 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sat, 27 Aug 2022 23:41:41 +0200 Subject: feat: implement named bindings --- macros/src/injectable_impl.rs | 200 +++++++++++++++--------------------------- 1 file changed, 72 insertions(+), 128 deletions(-) (limited to 'macros/src/injectable_impl.rs') diff --git a/macros/src/injectable_impl.rs b/macros/src/injectable_impl.rs index d74acb3..6edcab3 100644 --- a/macros/src/injectable_impl.rs +++ b/macros/src/injectable_impl.rs @@ -1,20 +1,20 @@ +use std::error::Error; + use quote::{format_ident, quote, ToTokens}; use syn::parse::{Parse, ParseStream}; use syn::Generics; -use syn::{ - parse_str, punctuated::Punctuated, token::Comma, ExprMethodCall, FnArg, ItemImpl, - Path, Type, TypePath, -}; +use syn::{parse_str, ExprMethodCall, FnArg, ItemImpl, Type}; -use crate::dependency_type::DependencyType; -use crate::util::item_impl::find_impl_method_by_name; +use crate::dependency::Dependency; +use crate::util::item_impl::find_impl_method_by_name_mut; +use crate::util::syn_path::syn_path_to_string; const DI_CONTAINER_VAR_NAME: &str = "di_container"; const DEPENDENCY_HISTORY_VAR_NAME: &str = "dependency_history"; pub struct InjectableImpl { - pub dependency_types: Vec, + pub dependencies: Vec, pub self_type: Type, pub generics: Generics, pub original_impl: ItemImpl, @@ -24,13 +24,13 @@ impl Parse for InjectableImpl { fn parse(input: ParseStream) -> syn::Result { - let impl_parsed_input = input.parse::()?; + let mut impl_parsed_input = input.parse::()?; - let dependency_types = Self::get_dependency_types(&impl_parsed_input) + let dependencies = Self::build_dependencies(&mut impl_parsed_input) .map_err(|err| input.error(err))?; Ok(Self { - dependency_types, + dependencies, self_type: impl_parsed_input.self_ty.as_ref().clone(), generics: impl_parsed_input.generics.clone(), original_impl: impl_parsed_input, @@ -43,7 +43,7 @@ impl InjectableImpl pub fn expand(&self, no_doc_hidden: bool) -> proc_macro2::TokenStream { let Self { - dependency_types, + dependencies, self_type, generics, original_impl, @@ -52,7 +52,7 @@ impl InjectableImpl let di_container_var = format_ident!("{}", DI_CONTAINER_VAR_NAME); let dependency_history_var = format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME); - let get_dep_method_calls = Self::create_get_dep_method_calls(dependency_types); + let get_dep_method_calls = Self::create_get_dep_method_calls(dependencies); let maybe_doc_hidden = if no_doc_hidden { quote! {} @@ -111,46 +111,38 @@ impl InjectableImpl } fn create_get_dep_method_calls( - dependency_types: &[DependencyType], + dependencies: &[Dependency], ) -> Vec { - dependency_types + dependencies .iter() - .filter_map(|dep_type| match &dep_type.interface { - Type::TraitObject(dep_type_trait) => { - let method_call = parse_str::( - format!( - "{}.get_bound::<{}>({}.clone())", - DI_CONTAINER_VAR_NAME, - dep_type_trait.to_token_stream(), - DEPENDENCY_HISTORY_VAR_NAME - ) - .as_str(), - ) - .ok()?; - - Some((method_call, dep_type)) - - /* - */ - } - Type::Path(dep_type_path) => { - let dep_type_path_str = Self::path_to_string(&dep_type_path.path); - - let method_call: ExprMethodCall = parse_str( - format!( - "{}.get_bound::<{}>({}.clone())", - DI_CONTAINER_VAR_NAME, - dep_type_path_str, - DEPENDENCY_HISTORY_VAR_NAME + .filter_map(|dependency| { + let dep_interface_str = match &dependency.interface { + Type::TraitObject(interface_trait) => { + Some(interface_trait.to_token_stream().to_string()) + } + Type::Path(path_interface) => { + Some(syn_path_to_string(&path_interface.path)) + } + &_ => None, + }?; + + let method_call = parse_str::( + format!( + "{}.get_bound::<{}>({}.clone(), {})", + DI_CONTAINER_VAR_NAME, + dep_interface_str, + DEPENDENCY_HISTORY_VAR_NAME, + dependency.name.as_ref().map_or_else( + || "None".to_string(), + |name| format!("Some(\"{}\")", name.value()) ) - .as_str(), ) - .ok()?; + .as_str(), + ) + .ok()?; - Some((method_call, dep_type)) - } - &_ => None, + Some((method_call, dependency)) }) .map(|(method_call, dep_type)| { let ptr_name = dep_type.ptr.to_string(); @@ -168,95 +160,47 @@ impl InjectableImpl .collect() } - #[allow(clippy::match_wildcard_for_single_variants)] - fn get_has_fn_args_self(fn_args: &Punctuated) -> bool - { - fn_args.iter().any(|arg| match arg { - FnArg::Receiver(_) => true, - &_ => false, - }) - } - - fn get_fn_arg_type_paths(fn_args: &Punctuated) -> 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 + fn build_dependencies( + item_impl: &mut ItemImpl, + ) -> Result, Box> { - let arg_type_path_string = Self::path_to_string(&type_path.path); - - 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> - { - let new_method_impl_item = find_impl_method_by_name(item_impl, "new") + let new_method_impl_item = find_impl_method_by_name_mut(item_impl, "new") .map_or_else(|| Err("Missing a 'new' method"), Ok)?; - let new_method_args = &new_method_impl_item.sig.inputs; + let new_method_args = &mut new_method_impl_item.sig.inputs; + + let dependencies: Result, _> = + new_method_args.iter().map(Dependency::build).collect(); + + for arg in new_method_args { + let typed_arg = if let FnArg::Typed(typed_arg) = arg { + typed_arg + } else { + continue; + }; + + let attrs_to_remove: Vec<_> = typed_arg + .attrs + .iter() + .enumerate() + .filter_map(|(index, attr)| { + if syn_path_to_string(&attr.path).as_str() == "syrette::named" { + return Some(index); + } - if Self::get_has_fn_args_self(new_method_args) { - return Err("Unexpected self argument in 'new' method"); - } + if attr.path.get_ident()?.to_string().as_str() == "named" { + return Some(index); + } - let new_method_arg_type_paths = Self::get_fn_arg_type_paths(new_method_args); + None + }) + .collect(); - 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"); + for attr_index in attrs_to_remove { + typed_arg.attrs.remove(attr_index); + } } - Ok(new_method_arg_type_paths - .iter() - .filter_map(|arg_type_path| DependencyType::from_type_path(arg_type_path)) - .collect()) + dependencies } } -- cgit v1.2.3-18-g5258