aboutsummaryrefslogtreecommitdiff
path: root/macros/src/injectable_impl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'macros/src/injectable_impl.rs')
-rw-r--r--macros/src/injectable_impl.rs200
1 files changed, 72 insertions, 128 deletions
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<DependencyType>,
+ pub dependencies: Vec<Dependency>,
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<Self>
{
- let impl_parsed_input = input.parse::<ItemImpl>()?;
+ let mut impl_parsed_input = input.parse::<ItemImpl>()?;
- 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<proc_macro2::TokenStream>
{
- dependency_types
+ dependencies
.iter()
- .filter_map(|dep_type| match &dep_type.interface {
- Type::TraitObject(dep_type_trait) => {
- let method_call = parse_str::<ExprMethodCall>(
- 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::<ExprMethodCall>(
+ 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<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
+ fn build_dependencies(
+ item_impl: &mut ItemImpl,
+ ) -> Result<Vec<Dependency>, Box<dyn Error>>
{
- 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<Vec<DependencyType>, &'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<Vec<_>, _> =
+ 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
}
}