aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2023-10-01 21:15:00 +0200
committerHampusM <hampus@hampusmat.com>2023-10-01 21:15:00 +0200
commitaf88321fc14a95b3613ec11a7f665db3c468c944 (patch)
tree723853d3788e559afa65c603a12b271e6872dd32
parent1fc0371867b02127a5da63f01f03d264b382b552 (diff)
refactor: remove impossible unwrap in injectable macro
This unwrap couldn't possibly be Err and can be removed by creating method call expressions by hand
-rw-r--r--macros/src/injectable/implementation.rs139
-rw-r--r--macros/src/lib.rs1
-rw-r--r--macros/src/util/mod.rs1
-rw-r--r--macros/src/util/syn_ext.rs114
-rw-r--r--macros/src/util/syn_path.rs26
5 files changed, 227 insertions, 54 deletions
diff --git a/macros/src/injectable/implementation.rs b/macros/src/injectable/implementation.rs
index 20c0d86..e2bcd3e 100644
--- a/macros/src/injectable/implementation.rs
+++ b/macros/src/injectable/implementation.rs
@@ -1,15 +1,33 @@
-use std::error::Error;
-
use proc_macro2::{Ident, Span};
use quote::{format_ident, quote, ToTokens};
use syn::spanned::Spanned;
-use syn::{parse2, ExprMethodCall, FnArg, ImplItemMethod, ItemImpl, ReturnType, Type};
+use syn::{
+ Expr,
+ ExprCall,
+ ExprLit,
+ ExprMethodCall,
+ ExprPath,
+ FnArg,
+ GenericMethodArgument,
+ ImplItemMethod,
+ ItemImpl,
+ MethodTurbofish,
+ ReturnType,
+ Type,
+};
use crate::injectable::dependency::{DependencyError, IDependency};
use crate::util::error::diagnostic_error_enum;
use crate::util::item_impl::find_impl_method_by_name_mut;
use crate::util::string::camelcase_to_snakecase;
-use crate::util::syn_path::SynPathExt;
+use crate::util::syn_ext::{
+ ExprCallExt,
+ ExprLitExt,
+ ExprMethodCallExt,
+ ExprPathExt,
+ MethodTurbofishExt,
+};
+use crate::util::syn_path::{syn_path, SynPathExt};
const DI_CONTAINER_VAR_NAME: &str = "di_container";
const DEPENDENCY_HISTORY_VAR_NAME: &str = "dependency_history";
@@ -152,8 +170,7 @@ impl<Dep: IDependency> InjectableImpl<Dep>
is_async,
&di_container_var,
&dependency_history_var,
- )
- .unwrap();
+ );
let injectable_impl = if is_async {
self.expand_async_impl(
@@ -311,7 +328,7 @@ impl<Dep: IDependency> InjectableImpl<Dep>
is_async: bool,
di_container_var: &Ident,
dependency_history_var: &Ident,
- ) -> Result<Vec<proc_macro2::TokenStream>, Box<dyn Error>>
+ ) -> Vec<proc_macro2::TokenStream>
{
dependencies
.iter()
@@ -326,27 +343,49 @@ impl<Dep: IDependency> InjectableImpl<Dep>
.collect()
}
+ fn create_binding_options(dependency: &Dep) -> Expr
+ {
+ let binding_options_new = Expr::Call(ExprCall::new(
+ Expr::Path(ExprPath::new(syn_path!(
+ syrette::di_container::BindingOptions::new
+ ))),
+ [],
+ ));
+
+ match dependency.get_name() {
+ Some(name) => Expr::MethodCall(ExprMethodCall::new(
+ binding_options_new,
+ format_ident!("name"),
+ [Expr::Lit(ExprLit::new(name.clone()))],
+ )),
+ None => binding_options_new,
+ }
+ }
+
fn create_single_get_dep_method_call(
dependency: &Dep,
is_async: bool,
di_container_var: &Ident,
dependency_history_var: &Ident,
- ) -> Result<proc_macro2::TokenStream, Box<dyn Error>>
+ ) -> proc_macro2::TokenStream
{
let dep_interface = dependency.get_interface();
- let maybe_name_fn = dependency
- .get_name()
- .as_ref()
- .map(|name| quote! { .name(#name) });
-
- let method_call = parse2::<ExprMethodCall>(quote! {
- #di_container_var.get_bound::<#dep_interface>(
- #dependency_history_var.clone(),
- syrette::di_container::BindingOptions::new()
- #maybe_name_fn
- )
- })?;
+ let method_call = ExprMethodCall::new(
+ Expr::Path(ExprPath::new(di_container_var.clone().into())),
+ format_ident!("get_bound"),
+ [
+ Expr::MethodCall(ExprMethodCall::new(
+ Expr::Path(ExprPath::new(dependency_history_var.clone().into())),
+ format_ident!("clone"),
+ [],
+ )),
+ Self::create_binding_options(dependency),
+ ],
+ )
+ .with_turbofish(MethodTurbofish::new([GenericMethodArgument::Type(
+ dep_interface.clone(),
+ )]));
let ptr_name = dependency.get_ptr().to_string();
@@ -367,7 +406,7 @@ impl<Dep: IDependency> InjectableImpl<Dep>
let dep_interface_str = dep_interface.to_token_stream().to_string();
- Ok(quote! {
+ quote! {
#do_method_call
.map_err(|err| #resolve_failed_error {
reason: Box::new(err),
@@ -378,7 +417,7 @@ impl<Dep: IDependency> InjectableImpl<Dep>
reason: err,
dependency_name: #dep_interface_str
})?
- })
+ }
}
fn build_dependencies(
@@ -793,14 +832,12 @@ mod tests
let di_container_var_ident = format_ident!("{}", DI_CONTAINER_VAR_NAME);
let dep_history_var_ident = format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME);
- let output =
- InjectableImpl::<MockIDependency>::create_single_get_dep_method_call(
- &mock_dependency,
- false,
- &format_ident!("{}", DI_CONTAINER_VAR_NAME),
- &format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME),
- )
- .unwrap();
+ let output = InjectableImpl::<MockIDependency>::create_single_get_dep_method_call(
+ &mock_dependency,
+ false,
+ &format_ident!("{}", DI_CONTAINER_VAR_NAME),
+ &format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME),
+ );
assert_eq!(
parse2::<Expr>(output).unwrap(),
@@ -847,14 +884,12 @@ mod tests
let di_container_var_ident = format_ident!("{}", DI_CONTAINER_VAR_NAME);
let dep_history_var_ident = format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME);
- let output =
- InjectableImpl::<MockIDependency>::create_single_get_dep_method_call(
- &mock_dependency,
- false,
- &format_ident!("{}", DI_CONTAINER_VAR_NAME),
- &format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME),
- )
- .unwrap();
+ let output = InjectableImpl::<MockIDependency>::create_single_get_dep_method_call(
+ &mock_dependency,
+ false,
+ &format_ident!("{}", DI_CONTAINER_VAR_NAME),
+ &format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME),
+ );
assert_eq!(
parse2::<Expr>(output).unwrap(),
@@ -899,14 +934,12 @@ mod tests
let di_container_var_ident = format_ident!("{}", DI_CONTAINER_VAR_NAME);
let dep_history_var_ident = format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME);
- let output =
- InjectableImpl::<MockIDependency>::create_single_get_dep_method_call(
- &mock_dependency,
- true,
- &format_ident!("{}", DI_CONTAINER_VAR_NAME),
- &format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME),
- )
- .unwrap();
+ let output = InjectableImpl::<MockIDependency>::create_single_get_dep_method_call(
+ &mock_dependency,
+ true,
+ &format_ident!("{}", DI_CONTAINER_VAR_NAME),
+ &format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME),
+ );
assert_eq!(
parse2::<Expr>(output).unwrap(),
@@ -954,14 +987,12 @@ mod tests
let di_container_var_ident = format_ident!("{}", DI_CONTAINER_VAR_NAME);
let dep_history_var_ident = format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME);
- let output =
- InjectableImpl::<MockIDependency>::create_single_get_dep_method_call(
- &mock_dependency,
- true,
- &format_ident!("{}", DI_CONTAINER_VAR_NAME),
- &format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME),
- )
- .unwrap();
+ let output = InjectableImpl::<MockIDependency>::create_single_get_dep_method_call(
+ &mock_dependency,
+ true,
+ &format_ident!("{}", DI_CONTAINER_VAR_NAME),
+ &format_ident!("{}", DEPENDENCY_HISTORY_VAR_NAME),
+ );
assert_eq!(
parse2::<Expr>(output).unwrap(),
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index 232483e..7928e03 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -1,5 +1,6 @@
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![deny(clippy::all, clippy::pedantic, missing_docs, unsafe_code)]
+#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::panic))]
#![allow(unknown_lints)]
#![allow(clippy::module_name_repetitions, clippy::manual_let_else)]
diff --git a/macros/src/util/mod.rs b/macros/src/util/mod.rs
index 2244229..7ab2185 100644
--- a/macros/src/util/mod.rs
+++ b/macros/src/util/mod.rs
@@ -2,6 +2,7 @@ pub mod error;
pub mod item_impl;
pub mod iterator_ext;
pub mod string;
+pub mod syn_ext;
pub mod syn_path;
pub mod tokens;
diff --git a/macros/src/util/syn_ext.rs b/macros/src/util/syn_ext.rs
new file mode 100644
index 0000000..6201670
--- /dev/null
+++ b/macros/src/util/syn_ext.rs
@@ -0,0 +1,114 @@
+use proc_macro2::Ident;
+use syn::punctuated::Punctuated;
+use syn::token::Paren;
+use syn::{
+ Expr,
+ ExprCall,
+ ExprLit,
+ ExprMethodCall,
+ ExprPath,
+ GenericMethodArgument,
+ Lit,
+ MethodTurbofish,
+ Path,
+ Token,
+};
+
+pub trait ExprMethodCallExt
+{
+ fn new(receiver: Expr, method: Ident, args: impl IntoIterator<Item = Expr>) -> Self;
+
+ fn with_turbofish(self, turbofish: MethodTurbofish) -> Self;
+}
+
+impl ExprMethodCallExt for ExprMethodCall
+{
+ fn new(receiver: Expr, method: Ident, args: impl IntoIterator<Item = Expr>) -> Self
+ {
+ Self {
+ attrs: Vec::new(),
+ receiver: Box::new(receiver),
+ dot_token: <Token![.]>::default(),
+ method,
+ turbofish: None,
+ paren_token: Paren::default(),
+ args: Punctuated::from_iter(args),
+ }
+ }
+
+ fn with_turbofish(mut self, turbofish: MethodTurbofish) -> Self
+ {
+ self.turbofish = Some(turbofish);
+
+ self
+ }
+}
+
+pub trait ExprPathExt
+{
+ fn new(path: Path) -> Self;
+}
+
+impl ExprPathExt for ExprPath
+{
+ fn new(path: Path) -> Self
+ {
+ Self {
+ attrs: Vec::new(),
+ qself: None,
+ path,
+ }
+ }
+}
+
+pub trait MethodTurbofishExt
+{
+ fn new(args: impl IntoIterator<Item = GenericMethodArgument>) -> Self;
+}
+
+impl MethodTurbofishExt for MethodTurbofish
+{
+ fn new(args: impl IntoIterator<Item = GenericMethodArgument>) -> Self
+ {
+ Self {
+ colon2_token: <Token![::]>::default(),
+ lt_token: <Token![<]>::default(),
+ args: Punctuated::from_iter(args),
+ gt_token: <Token![>]>::default(),
+ }
+ }
+}
+
+pub trait ExprCallExt
+{
+ fn new(function: Expr, args: impl IntoIterator<Item = Expr>) -> Self;
+}
+
+impl ExprCallExt for ExprCall
+{
+ fn new(function: Expr, args: impl IntoIterator<Item = Expr>) -> Self
+ {
+ Self {
+ attrs: Vec::new(),
+ func: Box::new(function),
+ paren_token: Paren::default(),
+ args: Punctuated::from_iter(args),
+ }
+ }
+}
+
+pub trait ExprLitExt
+{
+ fn new(lit: impl Into<Lit>) -> Self;
+}
+
+impl ExprLitExt for ExprLit
+{
+ fn new(lit: impl Into<Lit>) -> Self
+ {
+ Self {
+ attrs: Vec::new(),
+ lit: lit.into(),
+ }
+ }
+}
diff --git a/macros/src/util/syn_path.rs b/macros/src/util/syn_path.rs
index 88182cc..26e2597 100644
--- a/macros/src/util/syn_path.rs
+++ b/macros/src/util/syn_path.rs
@@ -32,3 +32,29 @@ impl SynPathExt for syn::Path
)
}
}
+
+macro_rules! syn_path {
+ ($first_segment: ident $(::$segment: ident)*) => {
+ ::syn::Path {
+ leading_colon: None,
+ segments: ::syn::punctuated::Punctuated::from_iter([
+ $crate::util::syn_path::syn_path_segment!($first_segment),
+ $($crate::util::syn_path::syn_path_segment!($segment),)*
+ ])
+ }
+ };
+}
+
+macro_rules! syn_path_segment {
+ ($segment: ident) => {
+ ::syn::PathSegment {
+ ident: ::proc_macro2::Ident::new(
+ stringify!($segment),
+ ::proc_macro2::Span::call_site(),
+ ),
+ arguments: ::syn::PathArguments::None,
+ }
+ };
+}
+
+pub(crate) use {syn_path, syn_path_segment};