From d6f01bd571753dc2e9628418f94f66139438bcb3 Mon Sep 17 00:00:00 2001 From: HampusM Date: Tue, 30 Aug 2022 18:53:23 +0200 Subject: refactor: replace arc cast panic with an error --- src/async_di_container.rs | 26 +++++++++++++++++++++----- src/errors/async_di_container.rs | 4 ++++ src/libs/intertrait/cast/arc.rs | 21 ++++++++++++++------- src/libs/intertrait/cast/box.rs | 4 ++-- src/libs/intertrait/cast/error.rs | 3 +++ src/libs/intertrait/cast/rc.rs | 4 ++-- src/libs/intertrait/mod.rs | 25 ++++++++----------------- 7 files changed, 54 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/async_di_container.rs b/src/async_di_container.rs index 374746f..ecf3a41 100644 --- a/src/async_di_container.rs +++ b/src/async_di_container.rs @@ -66,6 +66,7 @@ use crate::errors::async_di_container::{ AsyncDIContainerError, }; use crate::interfaces::async_injectable::AsyncInjectable; +use crate::libs::intertrait::cast::error::CastError; use crate::libs::intertrait::cast::{CastArc, CastBox}; use crate::provider::r#async::{ AsyncProvidable, @@ -410,11 +411,26 @@ impl AsyncDIContainer )) } AsyncProvidable::Singleton(singleton_binding) => { - Ok(SomeThreadsafePtr::ThreadsafeSingleton( - singleton_binding.cast::().map_err(|_| { - AsyncDIContainerError::CastFailed(type_name::()) - })?, - )) + Ok( + SomeThreadsafePtr::ThreadsafeSingleton( + singleton_binding.cast::().map_err( + |err| match err { + CastError::NotArcCastable(_) => { + AsyncDIContainerError::InterfaceNotAsync(type_name::< + Interface, + >( + )) + } + CastError::CastFailed { from: _, to: _ } => { + AsyncDIContainerError::CastFailed(type_name::< + Interface, + >( + )) + } + }, + )?, + ), + ) } #[cfg(feature = "factory")] AsyncProvidable::Factory(factory_binding) => { diff --git a/src/errors/async_di_container.rs b/src/errors/async_di_container.rs index 4f5e50a..bdb6fa0 100644 --- a/src/errors/async_di_container.rs +++ b/src/errors/async_di_container.rs @@ -43,6 +43,10 @@ pub enum AsyncDIContainerError /// The name of the binding if one exists. name: Option<&'static str>, }, + + /// A interface has not been marked async. + #[error("Interface '{0}' has not been marked async")] + InterfaceNotAsync(&'static str), } /// Error type for [`AsyncBindingBuilder`]. diff --git a/src/libs/intertrait/cast/arc.rs b/src/libs/intertrait/cast/arc.rs index 94c0482..33d84d2 100644 --- a/src/libs/intertrait/cast/arc.rs +++ b/src/libs/intertrait/cast/arc.rs @@ -13,7 +13,7 @@ use std::any::type_name; use std::sync::Arc; use crate::libs::intertrait::cast::error::CastError; -use crate::libs::intertrait::{caster, CastFromSync}; +use crate::libs::intertrait::{get_caster, CastFromSync}; pub trait CastArc { @@ -31,12 +31,19 @@ impl CastArc for CastFromSelf self: Arc, ) -> Result, CastError> { - match caster::((*self).type_id()) { - Some(caster) => Ok((caster.cast_arc)(self.arc_any())), - None => Err(CastError::CastFailed { - from: type_name::(), - to: type_name::(), - }), + let caster = get_caster::((*self).type_id()).map_or_else( + || { + Err(CastError::CastFailed { + from: type_name::(), + to: type_name::(), + }) + }, + Ok, + )?; + + match caster.opt_cast_arc { + Some(cast_arc) => Ok(cast_arc(self.arc_any())), + None => Err(CastError::NotArcCastable(type_name::())), } } } diff --git a/src/libs/intertrait/cast/box.rs b/src/libs/intertrait/cast/box.rs index 31f06db..c463c2f 100644 --- a/src/libs/intertrait/cast/box.rs +++ b/src/libs/intertrait/cast/box.rs @@ -13,7 +13,7 @@ use std::any::type_name; use crate::libs::intertrait::cast::error::CastError; -use crate::libs::intertrait::{caster, CastFrom}; +use crate::libs::intertrait::{get_caster, CastFrom}; pub trait CastBox { @@ -30,7 +30,7 @@ impl CastBox for CastFromSelf self: Box, ) -> Result, CastError> { - match caster::((*self).type_id()) { + match get_caster::((*self).type_id()) { Some(caster) => Ok((caster.cast_box)(self.box_any())), None => Err(CastError::CastFailed { from: type_name::(), diff --git a/src/libs/intertrait/cast/error.rs b/src/libs/intertrait/cast/error.rs index 74eb3ca..a834c05 100644 --- a/src/libs/intertrait/cast/error.rs +++ b/src/libs/intertrait/cast/error.rs @@ -7,4 +7,7 @@ pub enum CastError from: &'static str, to: &'static str, }, + + #[error("Trait '{0}' can't be cast to Arc")] + NotArcCastable(&'static str), } diff --git a/src/libs/intertrait/cast/rc.rs b/src/libs/intertrait/cast/rc.rs index dfb71c2..63c0024 100644 --- a/src/libs/intertrait/cast/rc.rs +++ b/src/libs/intertrait/cast/rc.rs @@ -13,7 +13,7 @@ use std::any::type_name; use std::rc::Rc; use crate::libs::intertrait::cast::error::CastError; -use crate::libs::intertrait::{caster, CastFrom}; +use crate::libs::intertrait::{get_caster, CastFrom}; pub trait CastRc { @@ -30,7 +30,7 @@ impl CastRc for CastFromSelf self: Rc, ) -> Result, CastError> { - match caster::((*self).type_id()) { + match get_caster::((*self).type_id()) { Some(caster) => Ok((caster.cast_rc)(self.rc_any())), None => Err(CastError::CastFailed { from: type_name::(), diff --git a/src/libs/intertrait/mod.rs b/src/libs/intertrait/mod.rs index bdae4c7..3b3e9ba 100644 --- a/src/libs/intertrait/mod.rs +++ b/src/libs/intertrait/mod.rs @@ -23,7 +23,7 @@ //! MIT license (LICENSE-MIT or ) //! //! at your option. -use std::any::{type_name, Any, TypeId}; +use std::any::{Any, TypeId}; use std::rc::Rc; use std::sync::Arc; @@ -58,22 +58,12 @@ static CASTER_MAP: Lazy> = Lazy::new(|| .collect() }); -fn cast_arc_panic(_: Arc) -> Arc -{ - panic!( - "Interface trait '{}' has not been marked async", - type_name::() - ) -} +type CastArcFn = fn(from: Arc) -> Arc; /// A `Caster` knows how to cast a reference to or `Box` of a trait object for `Any` /// to a trait object of trait `Trait`. Each `Caster` instance is specific to a concrete /// type. That is, it knows how to cast to single specific trait implemented by single /// specific type. -/// -/// An implementation of a trait for a concrete type doesn't need to manually provide -/// a `Caster`. Instead attach `#[cast_to]` to the `impl` block. -#[doc(hidden)] pub struct Caster { /// Casts a `Box` holding a trait object for `Any` to another `Box` holding a trait @@ -86,7 +76,7 @@ pub struct Caster /// Casts an `Arc` holding a trait object for `Any + Sync + Send + 'static` /// to another `Arc` holding a trait object for trait `Trait`. - pub cast_arc: fn(from: Arc) -> Arc, + pub opt_cast_arc: Option>, } impl Caster @@ -99,7 +89,7 @@ impl Caster Caster:: { cast_box, cast_rc, - cast_arc: cast_arc_panic, + opt_cast_arc: None, } } @@ -113,14 +103,15 @@ impl Caster Caster:: { cast_box, cast_rc, - cast_arc, + opt_cast_arc: Some(cast_arc), } } } /// Returns a `Caster` from a concrete type `S` to a trait `Trait` implemented /// by it. -fn caster(type_id: TypeId) -> Option<&'static Caster> +fn get_caster(type_id: TypeId) + -> Option<&'static Caster> { CASTER_MAP .get(&(type_id, TypeId::of::>())) @@ -250,7 +241,7 @@ mod tests let caster = Box::new(Caster:: { cast_box: |from| from.downcast::().unwrap(), cast_rc: |from| from.downcast::().unwrap(), - cast_arc: |from| from.downcast::().unwrap(), + opt_cast_arc: Some(|from| from.downcast::().unwrap()), }); (type_id, caster) } -- cgit v1.2.3-18-g5258