aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2022-11-06 17:20:45 +0100
committerHampusM <hampus@hampusmat.com>2022-11-06 17:20:45 +0100
commite282375de4ba75c69f7d619fc33c6250f6caba18 (patch)
treef09410f57ea154c834dba88d76510e2a27548956
parent2c03974a7e7cfec8d734caa6036d9a2461694818 (diff)
fix: allow declaring a concrete type as it's own interface
-rw-r--r--macros/src/declare_interface_args.rs10
-rw-r--r--macros/src/injectable/macro_args.rs3
-rw-r--r--macros/src/lib.rs50
-rw-r--r--macros/src/libs/intertrait_macros/gen_caster.rs14
4 files changed, 58 insertions, 19 deletions
diff --git a/macros/src/declare_interface_args.rs b/macros/src/declare_interface_args.rs
index bd2f24e..1641e38 100644
--- a/macros/src/declare_interface_args.rs
+++ b/macros/src/declare_interface_args.rs
@@ -1,6 +1,6 @@
use syn::parse::{Parse, ParseStream, Result};
use syn::punctuated::Punctuated;
-use syn::{Path, Token, Type};
+use syn::{Token, TypePath};
use crate::macro_flag::MacroFlag;
use crate::util::iterator_ext::IteratorExt;
@@ -9,8 +9,8 @@ pub const DECLARE_INTERFACE_FLAGS: &[&str] = &["async"];
pub struct DeclareInterfaceArgs
{
- pub implementation: Type,
- pub interface: Path,
+ pub implementation: TypePath,
+ pub interface: TypePath,
pub flags: Punctuated<MacroFlag, Token![,]>,
}
@@ -18,11 +18,11 @@ impl Parse for DeclareInterfaceArgs
{
fn parse(input: ParseStream) -> Result<Self>
{
- let implementation: Type = input.parse()?;
+ let implementation: TypePath = input.parse()?;
input.parse::<Token![->]>()?;
- let interface: Path = input.parse()?;
+ let interface: TypePath = input.parse()?;
let flags = if input.peek(Token![,]) {
input.parse::<Token![,]>()?;
diff --git a/macros/src/injectable/macro_args.rs b/macros/src/injectable/macro_args.rs
index 1dd06f8..6dd683b 100644
--- a/macros/src/injectable/macro_args.rs
+++ b/macros/src/injectable/macro_args.rs
@@ -5,7 +5,8 @@ use syn::{Token, TypePath};
use crate::macro_flag::MacroFlag;
use crate::util::iterator_ext::IteratorExt;
-pub const INJECTABLE_MACRO_FLAGS: &[&str] = &["no_doc_hidden", "async"];
+pub const INJECTABLE_MACRO_FLAGS: &[&str] =
+ &["no_doc_hidden", "async", "no_declare_concrete_interface"];
pub struct InjectableMacroArgs
{
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index 54c7951..832963e 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -8,7 +8,17 @@
use proc_macro::TokenStream;
use quote::quote;
-use syn::{parse, parse_macro_input};
+use syn::punctuated::Punctuated;
+use syn::token::Dyn;
+use syn::{
+ parse,
+ parse_macro_input,
+ TraitBound,
+ TraitBoundModifier,
+ Type,
+ TypeParamBound,
+ TypeTraitObject,
+};
mod declare_interface_args;
mod injectable;
@@ -43,16 +53,21 @@ use crate::libs::intertrait_macros::gen_caster::generate_caster;
/// # Flags
/// - `no_doc_hidden` - Don't hide the impl of the [`Injectable`] trait from
/// documentation.
+/// - `no_declare_concrete_interface` - Disable declaring the concrete type as the
+/// interface when no interface trait argument is given.
/// - `async` - Mark as async.
///
/// # Panics
/// If the attributed item is not a impl.
///
/// # Important
-/// If the interface trait argument is excluded, you should either manually
+/// When no interface trait argument is given, you should either manually
/// declare the interface with the [`declare_interface!`] macro or use
/// the [`di_container_bind`] macro to create a DI container binding.
///
+/// You can however also use the concrete type as the interface. As it is declared as such
+/// by default if the `no_declare_concrete_interface` flag is not set.
+///
/// # Attributes
/// Attributes specific to impls with this attribute macro.
///
@@ -127,6 +142,11 @@ pub fn injectable(args_stream: TokenStream, impl_stream: TokenStream) -> TokenSt
.find(|flag| flag.flag.to_string().as_str() == "no_doc_hidden")
.map_or(false, |flag| flag.is_on.value);
+ let no_declare_concrete_interface = flags
+ .iter()
+ .find(|flag| flag.flag.to_string().as_str() == "no_declare_concrete_interface")
+ .map_or(false, |flag| flag.is_on.value);
+
let is_async = flags
.iter()
.find(|flag| flag.flag.to_string().as_str() == "async")
@@ -141,9 +161,9 @@ pub fn injectable(args_stream: TokenStream, impl_stream: TokenStream) -> TokenSt
let expanded_injectable_impl = injectable_impl.expand(no_doc_hidden, is_async);
- let maybe_decl_interface = if interface.is_some() {
- let self_type = &injectable_impl.self_type;
+ let self_type = &injectable_impl.self_type;
+ let maybe_decl_interface = if interface.is_some() {
if is_async {
quote! {
syrette::declare_interface!(#self_type -> #interface, async = true);
@@ -153,6 +173,10 @@ pub fn injectable(args_stream: TokenStream, impl_stream: TokenStream) -> TokenSt
syrette::declare_interface!(#self_type -> #interface);
}
}
+ } else if !no_declare_concrete_interface {
+ quote! {
+ syrette::declare_interface!(#self_type -> #self_type);
+ }
} else {
quote! {}
};
@@ -210,7 +234,7 @@ pub fn injectable(args_stream: TokenStream, impl_stream: TokenStream) -> TokenSt
pub fn factory(args_stream: TokenStream, type_alias_stream: TokenStream) -> TokenStream
{
use quote::ToTokens;
- use syn::{parse_str, Type};
+ use syn::parse_str;
use crate::factory::build_declare_interfaces::build_declare_factory_interfaces;
use crate::factory::macro_args::FactoryMacroArgs;
@@ -393,7 +417,21 @@ pub fn declare_interface(input: TokenStream) -> TokenStream
let is_async =
opt_async_flag.map_or_else(|| false, |async_flag| async_flag.is_on.value);
- generate_caster(&implementation, &interface, is_async).into()
+ let interface_type = if interface == implementation {
+ Type::Path(interface)
+ } else {
+ Type::TraitObject(TypeTraitObject {
+ dyn_token: Some(Dyn::default()),
+ bounds: Punctuated::from_iter(vec![TypeParamBound::Trait(TraitBound {
+ paren_token: None,
+ modifier: TraitBoundModifier::None,
+ lifetimes: None,
+ path: interface.path,
+ })]),
+ })
+ };
+
+ generate_caster(&implementation, &interface_type, is_async).into()
}
/// Declares the name of a dependency.
diff --git a/macros/src/libs/intertrait_macros/gen_caster.rs b/macros/src/libs/intertrait_macros/gen_caster.rs
index a703a62..a76bb52 100644
--- a/macros/src/libs/intertrait_macros/gen_caster.rs
+++ b/macros/src/libs/intertrait_macros/gen_caster.rs
@@ -32,46 +32,46 @@ pub fn generate_caster(
let new_caster = if sync {
quote! {
- syrette::libs::intertrait::Caster::<dyn #dst_trait>::new_sync(
+ syrette::libs::intertrait::Caster::<#dst_trait>::new_sync(
|from| {
let concrete = from
.downcast::<#ty>()
.map_err(|_| syrette::libs::intertrait::CasterError::CastBoxFailed)?;
- Ok(concrete as Box<dyn #dst_trait>)
+ Ok(concrete as Box<#dst_trait>)
},
|from| {
let concrete = from
.downcast::<#ty>()
.map_err(|_| syrette::libs::intertrait::CasterError::CastRcFailed)?;
- Ok(concrete as std::rc::Rc<dyn #dst_trait>)
+ Ok(concrete as std::rc::Rc<#dst_trait>)
},
|from| {
let concrete = from
.downcast::<#ty>()
.map_err(|_| syrette::libs::intertrait::CasterError::CastArcFailed)?;
- Ok(concrete as std::sync::Arc<dyn #dst_trait>)
+ Ok(concrete as std::sync::Arc<#dst_trait>)
},
)
}
} else {
quote! {
- syrette::libs::intertrait::Caster::<dyn #dst_trait>::new(
+ syrette::libs::intertrait::Caster::<#dst_trait>::new(
|from| {
let concrete = from
.downcast::<#ty>()
.map_err(|_| syrette::libs::intertrait::CasterError::CastBoxFailed)?;
- Ok(concrete as Box<dyn #dst_trait>)
+ Ok(concrete as Box<#dst_trait>)
},
|from| {
let concrete = from
.downcast::<#ty>()
.map_err(|_| syrette::libs::intertrait::CasterError::CastRcFailed)?;
- Ok(concrete as std::rc::Rc<dyn #dst_trait>)
+ Ok(concrete as std::rc::Rc<#dst_trait>)
},
)
}