From e282375de4ba75c69f7d619fc33c6250f6caba18 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 6 Nov 2022 17:20:45 +0100 Subject: fix: allow declaring a concrete type as it's own interface --- macros/src/declare_interface_args.rs | 10 ++--- macros/src/injectable/macro_args.rs | 3 +- macros/src/lib.rs | 50 ++++++++++++++++++++++--- macros/src/libs/intertrait_macros/gen_caster.rs | 14 +++---- 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, } @@ -18,11 +18,11 @@ impl Parse for DeclareInterfaceArgs { fn parse(input: ParseStream) -> Result { - let implementation: Type = input.parse()?; + let implementation: TypePath = input.parse()?; input.parse::]>()?; - let interface: Path = input.parse()?; + let interface: TypePath = input.parse()?; let flags = if input.peek(Token![,]) { input.parse::()?; 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::::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) + 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) + 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) + Ok(concrete as std::sync::Arc<#dst_trait>) }, ) } } else { quote! { - syrette::libs::intertrait::Caster::::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) + 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) + Ok(concrete as std::rc::Rc<#dst_trait>) }, ) } -- cgit v1.2.3-18-g5258