From 8c66b98bca6ed0a2990903fe8e0ea72def5c7be8 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 21 Aug 2022 14:19:07 +0200 Subject: refactor!: change errors to be more sane BREAKING CHANGE: Major improvements have been made to error types and the error_stack crate is no longer used --- Cargo.toml | 4 +- examples/unbound/animal_store.rs | 34 +++++++ examples/unbound/animals/human.rs | 20 +++-- examples/unbound/bootstrap.rs | 7 ++ examples/unbound/interfaces/animal_store.rs | 11 +++ examples/unbound/interfaces/mod.rs | 1 + examples/unbound/main.rs | 9 +- examples/with-3rd-party/bootstrap.rs | 5 +- examples/with-3rd-party/main.rs | 25 +----- macros/src/injectable_impl.rs | 39 ++++---- src/di_container.rs | 134 +++++++++++----------------- src/di_container_binding_map.rs | 10 +-- src/errors/di_container.rs | 75 +++++++++++----- src/errors/injectable.rs | 41 ++++++--- src/interfaces/any_factory.rs | 10 +++ src/interfaces/injectable.rs | 14 ++- src/libs/intertrait/cast/arc.rs | 15 ++-- src/libs/intertrait/cast/box.rs | 15 ++-- src/libs/intertrait/cast/error.rs | 21 ++--- src/libs/intertrait/cast/rc.rs | 15 ++-- src/libs/mod.rs | 1 - src/provider.rs | 11 +-- 22 files changed, 281 insertions(+), 236 deletions(-) create mode 100644 examples/unbound/animal_store.rs create mode 100644 examples/unbound/interfaces/animal_store.rs diff --git a/Cargo.toml b/Cargo.toml index d49ab8c..b3b830b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,8 +28,10 @@ required-features = ["factory"] syrette_macros = { path = "./macros", version = "0.2.1" } linkme = "0.3.0" once_cell = "1.4" -error-stack = "0.1.1" ahash = "0.7.6" +thiserror = "1.0.32" +strum = "0.24.1" +strum_macros = "0.24.3" [dev_dependencies] mockall = "0.11.1" diff --git a/examples/unbound/animal_store.rs b/examples/unbound/animal_store.rs new file mode 100644 index 0000000..b2127e4 --- /dev/null +++ b/examples/unbound/animal_store.rs @@ -0,0 +1,34 @@ +use syrette::injectable; +use syrette::ptr::{SingletonPtr, TransientPtr}; + +use crate::interfaces::animal_store::IAnimalStore; +use crate::interfaces::cat::ICat; +use crate::interfaces::dog::IDog; + +pub struct AnimalStore +{ + dog: SingletonPtr, + cat: TransientPtr, +} + +#[injectable] +impl AnimalStore +{ + fn new(dog: SingletonPtr, cat: TransientPtr) -> Self + { + Self { dog, cat } + } +} + +impl IAnimalStore for AnimalStore +{ + fn get_dog(&self) -> SingletonPtr + { + self.dog.clone() + } + + fn get_cat(&self) -> &TransientPtr + { + &self.cat + } +} diff --git a/examples/unbound/animals/human.rs b/examples/unbound/animals/human.rs index d9b848b..56764d3 100644 --- a/examples/unbound/animals/human.rs +++ b/examples/unbound/animals/human.rs @@ -1,22 +1,20 @@ use syrette::injectable; -use syrette::ptr::{SingletonPtr, TransientPtr}; +use syrette::ptr::TransientPtr; -use crate::interfaces::cat::ICat; -use crate::interfaces::dog::IDog; +use crate::interfaces::animal_store::IAnimalStore; use crate::interfaces::human::IHuman; pub struct Human { - dog: SingletonPtr, - cat: TransientPtr, + animal_store: TransientPtr, } #[injectable(IHuman)] impl Human { - pub fn new(dog: SingletonPtr, cat: TransientPtr) -> Self + pub fn new(animal_store: TransientPtr) -> Self { - Self { dog, cat } + Self { animal_store } } } @@ -24,12 +22,16 @@ impl IHuman for Human { fn make_pets_make_sounds(&self) { + let dog = self.animal_store.get_dog(); + println!("Hi doggy!"); - self.dog.woof(); + dog.woof(); + + let cat = self.animal_store.get_cat(); println!("Hi kitty!"); - self.cat.meow(); + cat.meow(); } } diff --git a/examples/unbound/bootstrap.rs b/examples/unbound/bootstrap.rs index 7835619..dc8468c 100644 --- a/examples/unbound/bootstrap.rs +++ b/examples/unbound/bootstrap.rs @@ -1,10 +1,12 @@ use syrette::DIContainer; // Concrete implementations +use crate::animal_store::AnimalStore; use crate::animals::dog::Dog; use crate::animals::human::Human; // // Interfaces +use crate::interfaces::animal_store::IAnimalStore; use crate::interfaces::dog::IDog; use crate::interfaces::human::IHuman; @@ -19,5 +21,10 @@ pub fn bootstrap() -> DIContainer di_container.bind::().to::().unwrap(); + di_container + .bind::() + .to::() + .unwrap(); + di_container } diff --git a/examples/unbound/interfaces/animal_store.rs b/examples/unbound/interfaces/animal_store.rs new file mode 100644 index 0000000..dc8a4c3 --- /dev/null +++ b/examples/unbound/interfaces/animal_store.rs @@ -0,0 +1,11 @@ +use syrette::ptr::{SingletonPtr, TransientPtr}; + +use crate::interfaces::cat::ICat; +use crate::interfaces::dog::IDog; + +pub trait IAnimalStore +{ + fn get_dog(&self) -> SingletonPtr; + + fn get_cat(&self) -> &TransientPtr; +} diff --git a/examples/unbound/interfaces/mod.rs b/examples/unbound/interfaces/mod.rs index 5444978..bd9f848 100644 --- a/examples/unbound/interfaces/mod.rs +++ b/examples/unbound/interfaces/mod.rs @@ -1,3 +1,4 @@ +pub mod animal_store; pub mod cat; pub mod dog; pub mod human; diff --git a/examples/unbound/main.rs b/examples/unbound/main.rs index 3a937c3..47629e4 100644 --- a/examples/unbound/main.rs +++ b/examples/unbound/main.rs @@ -2,6 +2,9 @@ #![deny(clippy::pedantic)] #![allow(clippy::module_name_repetitions)] +use std::error::Error; + +mod animal_store; mod animals; mod bootstrap; mod interfaces; @@ -10,7 +13,7 @@ use bootstrap::bootstrap; use interfaces::dog::IDog; use interfaces::human::IHuman; -fn main() +fn main() -> Result<(), Box> { println!("Hello, world!"); @@ -20,7 +23,9 @@ fn main() dog.woof(); - let human = di_container.get::().unwrap(); + let human = di_container.get::()?; human.make_pets_make_sounds(); + + Ok(()) } diff --git a/examples/with-3rd-party/bootstrap.rs b/examples/with-3rd-party/bootstrap.rs index 1ab3192..49de7fa 100644 --- a/examples/with-3rd-party/bootstrap.rs +++ b/examples/with-3rd-party/bootstrap.rs @@ -1,4 +1,5 @@ -use syrette::errors::di_container::BindingBuilderError; +use std::error::Error; + use syrette::ptr::TransientPtr; use syrette::{declare_default_factory, DIContainer}; use third_party_lib::Shuriken; @@ -11,7 +12,7 @@ use crate::ninja::Ninja; declare_default_factory!(Shuriken); -pub fn bootstrap() -> error_stack::Result +pub fn bootstrap() -> Result> { let mut di_container: DIContainer = DIContainer::new(); diff --git a/examples/with-3rd-party/main.rs b/examples/with-3rd-party/main.rs index f615ff5..dd4c21f 100644 --- a/examples/with-3rd-party/main.rs +++ b/examples/with-3rd-party/main.rs @@ -2,39 +2,22 @@ #![deny(clippy::pedantic)] #![allow(clippy::module_name_repetitions)] -use std::fmt::Display; +use std::error::Error; mod bootstrap; mod interfaces; mod ninja; -use error_stack::{Context, ResultExt}; - use crate::bootstrap::bootstrap; use crate::interfaces::ninja::INinja; -#[derive(Debug)] -struct ApplicationError; - -impl Display for ApplicationError -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result - { - f.write_str("An application error has occurred") - } -} - -impl Context for ApplicationError {} - -fn main() -> error_stack::Result<(), ApplicationError> +fn main() -> Result<(), Box> { println!("Hello, world!"); - let di_container = bootstrap().change_context(ApplicationError)?; + let di_container = bootstrap()?; - let ninja = di_container - .get::() - .change_context(ApplicationError)?; + let ninja = di_container.get::()?; ninja.throw_shuriken(); diff --git a/macros/src/injectable_impl.rs b/macros/src/injectable_impl.rs index d125f05..bc70be9 100644 --- a/macros/src/injectable_impl.rs +++ b/macros/src/injectable_impl.rs @@ -66,16 +66,13 @@ impl InjectableImpl if #dependency_history_var.contains(&self_type_name) { #dependency_history_var.push(self_type_name); - return Err( - report!(ResolveError) - .attach_printable(format!( - "Detected circular dependencies. {}", - syrette::dependency_trace::create_dependency_trace( - #dependency_history_var.as_slice(), - self_type_name - ) - )) - ); + let dependency_trace = + syrette::dependency_trace::create_dependency_trace( + #dependency_history_var.as_slice(), + self_type_name + ); + + return Err(InjectableError::DetectedCircular {dependency_trace }); } #dependency_history_var.push(self_type_name); @@ -92,26 +89,24 @@ impl InjectableImpl fn resolve( #di_container_var: &syrette::DIContainer, mut #dependency_history_var: Vec<&'static str>, - ) -> syrette::libs::error_stack::Result< + ) -> Result< syrette::ptr::TransientPtr, - syrette::errors::injectable::ResolveError> + syrette::errors::injectable::InjectableError> { - use syrette::libs::error_stack::{ResultExt, report}; - use syrette::errors::injectable::ResolveError; + use std::any::type_name; + + use syrette::errors::injectable::InjectableError; - let self_type_name = std::any::type_name::<#self_type>(); + let self_type_name = type_name::<#self_type>(); #maybe_prevent_circular_deps return Ok(syrette::ptr::TransientPtr::new(Self::new( #(#get_dep_method_calls - .change_context(ResolveError) - .attach_printable( - format!( - "Unable to resolve a dependency of {}", - self_type_name - ) - )? + .map_err(|err| InjectableError::ResolveFailed { + reason: Box::new(err), + affected: self_type_name + })? ),* ))); } diff --git a/src/di_container.rs b/src/di_container.rs index 84fb9e0..c698fac 100644 --- a/src/di_container.rs +++ b/src/di_container.rs @@ -50,29 +50,15 @@ use std::any::type_name; use std::marker::PhantomData; -use error_stack::{report, Report, ResultExt}; - #[cfg(feature = "factory")] use crate::castable_factory::CastableFactory; use crate::di_container_binding_map::DIContainerBindingMap; use crate::errors::di_container::{BindingBuilderError, DIContainerError}; use crate::interfaces::injectable::Injectable; -use crate::libs::intertrait::cast::error::CastError; use crate::libs::intertrait::cast::{CastBox, CastRc}; use crate::provider::{Providable, SingletonProvider, TransientTypeProvider}; use crate::ptr::{SingletonPtr, TransientPtr}; -fn unable_to_cast_binding(err: Report) -> Report -where - Interface: 'static + ?Sized, -{ - err.change_context(DIContainerError) - .attach_printable(format!( - "Unable to cast binding for interface '{}'", - type_name::() - )) -} - /// Binding builder for type `Interface` inside a [`DIContainer`]. pub struct BindingBuilder<'di_container_lt, Interface> where @@ -100,7 +86,7 @@ where /// # Errors /// Will return Err if the associated [`DIContainer`] already have a binding for /// the interface. - pub fn to(&mut self) -> error_stack::Result<(), BindingBuilderError> + pub fn to(&mut self) -> Result<(), BindingBuilderError> where Implementation: Injectable, { @@ -108,10 +94,7 @@ where .bindings .set::(Box::new(TransientTypeProvider::::new())) .ok_or_else(|| { - report!(BindingBuilderError).attach_printable(format!( - "Binding already exists for interface '{}'", - type_name::() - )) + BindingBuilderError::BindingAlreadyExists(type_name::()) })?; Ok(()) @@ -123,25 +106,20 @@ where /// # Errors /// Will return Err if creating the singleton fails or if the /// associated [`DIContainer`] already have a binding for the interface. - pub fn to_singleton( - &mut self, - ) -> error_stack::Result<(), BindingBuilderError> + pub fn to_singleton(&mut self) -> Result<(), BindingBuilderError> where Implementation: Injectable, { let singleton: SingletonPtr = SingletonPtr::from( Implementation::resolve(self.di_container, Vec::new()) - .change_context(BindingBuilderError)?, + .map_err(BindingBuilderError::SingletonResolveFailed)?, ); self.di_container .bindings .set::(Box::new(SingletonProvider::new(singleton))) .ok_or_else(|| { - report!(BindingBuilderError).attach_printable(format!( - "Binding already exists for interface '{}'", - type_name::() - )) + BindingBuilderError::BindingAlreadyExists(type_name::()) })?; Ok(()) @@ -159,7 +137,7 @@ where pub fn to_factory( &mut self, factory_func: &'static dyn Fn>, - ) -> error_stack::Result<(), BindingBuilderError> + ) -> Result<(), BindingBuilderError> where Args: 'static, Return: 'static + ?Sized, @@ -173,10 +151,7 @@ where crate::ptr::FactoryPtr::new(factory_impl), ))) .ok_or_else(|| { - report!(BindingBuilderError).attach_printable(format!( - "Binding already exists for interface '{}'", - type_name::() - )) + BindingBuilderError::BindingAlreadyExists(type_name::()) })?; Ok(()) @@ -194,7 +169,7 @@ where pub fn to_default_factory( &mut self, factory_func: &'static dyn Fn<(), Output = TransientPtr>, - ) -> error_stack::Result<(), BindingBuilderError> + ) -> Result<(), BindingBuilderError> where Return: 'static + ?Sized, { @@ -206,10 +181,7 @@ where crate::ptr::FactoryPtr::new(factory_impl), ))) .ok_or_else(|| { - report!(BindingBuilderError).attach_printable(format!( - "Binding already exists for interface '{}'", - type_name::() - )) + BindingBuilderError::BindingAlreadyExists(type_name::()) })?; Ok(()) @@ -249,9 +221,7 @@ impl DIContainer /// - Resolving the binding for `Interface` fails /// - Casting the binding for `Interface` fails /// - The binding for `Interface` is not transient - pub fn get( - &self, - ) -> error_stack::Result, DIContainerError> + pub fn get(&self) -> Result, DIContainerError> where Interface: 'static + ?Sized, { @@ -268,7 +238,7 @@ impl DIContainer /// - The binding for `Interface` is not a singleton pub fn get_singleton( &self, - ) -> error_stack::Result, DIContainerError> + ) -> Result, DIContainerError> where Interface: 'static + ?Sized, { @@ -288,7 +258,7 @@ impl DIContainer #[cfg(feature = "factory")] pub fn get_factory( &self, - ) -> error_stack::Result, DIContainerError> + ) -> Result, DIContainerError> where Interface: 'static + ?Sized, { @@ -297,20 +267,21 @@ impl DIContainer if let Providable::Factory(binding_factory) = binding_providable { return binding_factory .cast::() - .map_err(unable_to_cast_binding::); + .map_err(|_| DIContainerError::CastFailed(type_name::())); } - Err(report!(DIContainerError).attach_printable(format!( - "Binding for interface '{}' is not a factory", - type_name::() - ))) + Err(DIContainerError::WrongBindingType { + interface: type_name::(), + expected: "factory", + found: binding_providable.to_string().to_lowercase(), + }) } #[doc(hidden)] pub fn get_with_history( &self, dependency_history: Vec<&'static str>, - ) -> error_stack::Result, DIContainerError> + ) -> Result, DIContainerError> where Interface: 'static + ?Sized, { @@ -320,7 +291,7 @@ impl DIContainer if let Providable::Transient(binding_transient) = binding_providable { return binding_transient .cast::() - .map_err(unable_to_cast_binding::); + .map_err(|_| DIContainerError::CastFailed(type_name::())); } #[cfg(feature = "factory")] @@ -329,22 +300,23 @@ impl DIContainer let factory = binding_factory .cast::>() - .map_err(unable_to_cast_binding::)?; + .map_err(|_| DIContainerError::CastFailed(type_name::()))?; return Ok(factory()); } - Err(report!(DIContainerError).attach_printable(format!( - "Binding for interface '{}' is not transient", - type_name::() - ))) + Err(DIContainerError::WrongBindingType { + interface: type_name::(), + expected: "transient", + found: binding_providable.to_string().to_lowercase(), + }) } #[doc(hidden)] pub fn get_singleton_with_history( &self, dependency_history: Vec<&'static str>, - ) -> error_stack::Result, DIContainerError> + ) -> Result, DIContainerError> where Interface: 'static + ?Sized, { @@ -354,30 +326,30 @@ impl DIContainer if let Providable::Singleton(binding_singleton) = binding_providable { return binding_singleton .cast::() - .map_err(unable_to_cast_binding::); + .map_err(|_| DIContainerError::CastFailed(type_name::())); } - Err(report!(DIContainerError).attach_printable(format!( - "Binding for interface '{}' is not a singleton", - type_name::() - ))) + Err(DIContainerError::WrongBindingType { + interface: type_name::(), + expected: "singleton", + found: binding_providable.to_string().to_lowercase(), + }) } fn get_binding_providable( &self, dependency_history: Vec<&'static str>, - ) -> error_stack::Result + ) -> Result where Interface: 'static + ?Sized, { self.bindings .get::()? .provide(self, dependency_history) - .change_context(DIContainerError) - .attach_printable(format!( - "Failed to resolve binding for interface '{}'", - type_name::() - )) + .map_err(|err| DIContainerError::BindingResolveFailed { + reason: err, + interface: type_name::(), + }) } } @@ -395,7 +367,7 @@ mod tests use mockall::mock; use super::*; - use crate::errors::injectable::ResolveError; + use crate::errors::injectable::InjectableError; use crate::provider::IProvider; use crate::ptr::TransientPtr; @@ -450,10 +422,7 @@ mod tests fn resolve( _di_container: &DIContainer, _dependency_history: Vec<&'static str>, - ) -> error_stack::Result< - TransientPtr, - crate::errors::injectable::ResolveError, - > + ) -> Result, crate::errors::injectable::InjectableError> where Self: Sized, { @@ -517,10 +486,7 @@ mod tests fn resolve( _di_container: &DIContainer, _dependency_history: Vec<&'static str>, - ) -> error_stack::Result< - TransientPtr, - crate::errors::injectable::ResolveError, - > + ) -> Result, crate::errors::injectable::InjectableError> where Self: Sized, { @@ -530,7 +496,7 @@ mod tests } #[test] - fn can_bind_to() -> error_stack::Result<(), BindingBuilderError> + fn can_bind_to() -> Result<(), BindingBuilderError> { let mut di_container: DIContainer = DIContainer::new(); @@ -546,7 +512,7 @@ mod tests } #[test] - fn can_bind_to_singleton() -> error_stack::Result<(), BindingBuilderError> + fn can_bind_to_singleton() -> Result<(), BindingBuilderError> { let mut di_container: DIContainer = DIContainer::new(); @@ -563,7 +529,7 @@ mod tests #[test] #[cfg(feature = "factory")] - fn can_bind_to_factory() -> error_stack::Result<(), BindingBuilderError> + fn can_bind_to_factory() -> Result<(), BindingBuilderError> { type IUserManagerFactory = dyn crate::interfaces::factory::IFactory<(), dyn subjects::IUserManager>; @@ -585,7 +551,7 @@ mod tests } #[test] - fn can_get() -> error_stack::Result<(), DIContainerError> + fn can_get() -> Result<(), DIContainerError> { mock! { Provider {} @@ -596,7 +562,7 @@ mod tests &self, di_container: &DIContainer, dependency_history: Vec<&'static str>, - ) -> error_stack::Result; + ) -> Result; } } @@ -620,7 +586,7 @@ mod tests } #[test] - fn can_get_singleton() -> error_stack::Result<(), DIContainerError> + fn can_get_singleton() -> Result<(), DIContainerError> { mock! { Provider {} @@ -631,7 +597,7 @@ mod tests &self, di_container: &DIContainer, dependency_history: Vec<&'static str>, - ) -> error_stack::Result; + ) -> Result; } } @@ -664,7 +630,7 @@ mod tests #[test] #[cfg(feature = "factory")] - fn can_get_factory() -> error_stack::Result<(), DIContainerError> + fn can_get_factory() -> Result<(), DIContainerError> { trait IUserManager { @@ -717,7 +683,7 @@ mod tests &self, di_container: &DIContainer, dependency_history: Vec<&'static str>, - ) -> error_stack::Result; + ) -> Result; } } diff --git a/src/di_container_binding_map.rs b/src/di_container_binding_map.rs index fee33b0..e64ff17 100644 --- a/src/di_container_binding_map.rs +++ b/src/di_container_binding_map.rs @@ -1,7 +1,6 @@ use std::any::{type_name, TypeId}; use ahash::AHashMap; -use error_stack::report; use crate::{errors::di_container::DIContainerError, provider::IProvider}; @@ -19,7 +18,7 @@ impl DIContainerBindingMap } } - pub fn get(&self) -> error_stack::Result<&dyn IProvider, DIContainerError> + pub fn get(&self) -> Result<&dyn IProvider, DIContainerError> where Interface: 'static + ?Sized, { @@ -28,12 +27,7 @@ impl DIContainerBindingMap Ok(self .bindings .get(&interface_typeid) - .ok_or_else(|| { - report!(DIContainerError).attach_printable(format!( - "No binding exists for interface '{}'", - type_name::() - )) - })? + .ok_or_else(|| DIContainerError::BindingNotFound(type_name::()))? .as_ref()) } diff --git a/src/errors/di_container.rs b/src/errors/di_container.rs index 127676f..ed05a5e 100644 --- a/src/errors/di_container.rs +++ b/src/errors/di_container.rs @@ -1,34 +1,61 @@ -//! Error types for the DI container. +//! Error types for [`DIContainer`] and it's related structs. +//! +//! [`DIContainer`]: crate::di_container::DIContainer -use std::fmt; -use std::fmt::{Display, Formatter}; +use crate::errors::injectable::InjectableError; -use error_stack::Context; - -/// Error for when the DI container fails to do something. -#[derive(Debug)] -pub struct DIContainerError; - -impl Display for DIContainerError +/// Error type for [`DIContainer`]. +/// +/// [`DIContainer`]: crate::di_container::DIContainer +#[derive(thiserror::Error, Debug)] +pub enum DIContainerError { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result + /// Unable to cast a binding for a interface. + #[error("Unable to cast binding for interface '{0}'")] + CastFailed(&'static str), + + /// Wrong binding type. + #[error("Wrong binding type for interface '{interface}'. Expected a {expected}. Found a {found}")] + WrongBindingType { - fmt.write_str("A DI container error has occurred") - } -} + /// The affected bound interface. + interface: &'static str, -impl Context for DIContainerError {} + /// The expected binding type. + expected: &'static str, -/// Error for when the binding builder fails to do something. -#[derive(Debug)] -pub struct BindingBuilderError; + /// The found binding type. + found: String, + }, -impl Display for BindingBuilderError -{ - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result + /// Failed to resolve a binding for a interface. + #[error("Failed to resolve binding for interface '{interface}'")] + BindingResolveFailed { - fmt.write_str("A binding builder error has occurred") - } + /// The reason for the problem. + #[source] + reason: InjectableError, + + /// The affected bound interface. + interface: &'static str, + }, + + /// No binding exists for a interface. + #[error("No binding exists for interface '{0}'")] + BindingNotFound(&'static str), } -impl Context for BindingBuilderError {} +/// Error type for [`BindingBuilder`]. +/// +/// [`BindingBuilder`]: crate::di_container::BindingBuilder +#[derive(thiserror::Error, Debug)] +pub enum BindingBuilderError +{ + /// A binding already exists for a interface. + #[error("Binding already exists for interface '{0}'")] + BindingAlreadyExists(&'static str), + + /// Resolving a singleton failed. + #[error("Resolving the given singleton failed")] + SingletonResolveFailed(#[from] InjectableError), +} diff --git a/src/errors/injectable.rs b/src/errors/injectable.rs index 63afa11..4b9af96 100644 --- a/src/errors/injectable.rs +++ b/src/errors/injectable.rs @@ -1,20 +1,33 @@ -//! Error types for structs implementing Injectable. +#![allow(clippy::module_name_repetitions)] +//! Error types for structs that implement [`Injectable`]. +//! +//! [`Injectable`]: crate::interfaces::injectable::Injectable -use core::fmt; -use std::fmt::{Display, Formatter}; +use super::di_container::DIContainerError; -use error_stack::Context; +/// Error type for structs that implement [`Injectable`]. +/// +/// [`Injectable`]: crate::interfaces::injectable::Injectable +#[derive(thiserror::Error, Debug)] +pub enum InjectableError +{ + /// Failed to resolve dependencies. + #[error("Failed to resolve a dependency of '{affected}'")] + ResolveFailed + { + /// The reason for the problem. + #[source] + reason: Box, -/// Error for when a injectable struct fails to be resolved. -#[derive(Debug)] -pub struct ResolveError; + /// The affected injectable type. + affected: &'static str, + }, -impl Display for ResolveError -{ - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result + /// Detected circular dependencies. + #[error("Detected circular dependencies. {dependency_trace}")] + DetectedCircular { - fmt.write_str("Failed to resolve injectable struct") - } + /// A visual trace of dependencies. + dependency_trace: String, + }, } - -impl Context for ResolveError {} diff --git a/src/interfaces/any_factory.rs b/src/interfaces/any_factory.rs index 98ec144..887bb61 100644 --- a/src/interfaces/any_factory.rs +++ b/src/interfaces/any_factory.rs @@ -1,6 +1,16 @@ //! Interface for any factory to ever exist. +use std::fmt::Debug; + use crate::libs::intertrait::CastFrom; /// Interface for any factory to ever exist. pub trait AnyFactory: CastFrom {} + +impl Debug for dyn AnyFactory +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result + { + f.write_str("{}") + } +} diff --git a/src/interfaces/injectable.rs b/src/interfaces/injectable.rs index e6e4ced..f90b79d 100644 --- a/src/interfaces/injectable.rs +++ b/src/interfaces/injectable.rs @@ -1,5 +1,7 @@ //! Interface for structs that can be injected into or be injected to. -use crate::errors::injectable::ResolveError; +use std::fmt::Debug; + +use crate::errors::injectable::InjectableError; use crate::libs::intertrait::CastFrom; use crate::ptr::TransientPtr; use crate::DIContainer; @@ -14,7 +16,15 @@ pub trait Injectable: CastFrom fn resolve( di_container: &DIContainer, dependency_history: Vec<&'static str>, - ) -> error_stack::Result, ResolveError> + ) -> Result, InjectableError> where Self: Sized; } + +impl Debug for dyn Injectable +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result + { + f.write_str("{}") + } +} diff --git a/src/libs/intertrait/cast/arc.rs b/src/libs/intertrait/cast/arc.rs index f8e0f11..65ae1ef 100644 --- a/src/libs/intertrait/cast/arc.rs +++ b/src/libs/intertrait/cast/arc.rs @@ -12,8 +12,6 @@ use std::any::type_name; use std::sync::Arc; -use error_stack::report; - use crate::libs::intertrait::cast::error::CastError; use crate::libs::intertrait::{caster, CastFromSync}; @@ -22,7 +20,7 @@ pub trait CastArc /// Casts an `Arc` for this trait into that for type `OtherTrait`. fn cast( self: Arc, - ) -> error_stack::Result, CastError>; + ) -> Result, CastError>; } /// A blanket implementation of `CastArc` for traits extending `CastFrom`, `Sync`, and `Send`. @@ -30,15 +28,14 @@ impl CastArc for CastFromSelf { fn cast( self: Arc, - ) -> error_stack::Result, CastError> + ) -> Result, CastError> { match caster::((*self).type_id()) { Some(caster) => Ok((caster.cast_arc)(self.arc_any())), - None => Err(report!(CastError).attach_printable(format!( - "From {} to {}", - type_name::(), - type_name::() - ))), + None => Err(CastError::CastFailed { + from: type_name::(), + to: type_name::(), + }), } } } diff --git a/src/libs/intertrait/cast/box.rs b/src/libs/intertrait/cast/box.rs index 11f631a..31f06db 100644 --- a/src/libs/intertrait/cast/box.rs +++ b/src/libs/intertrait/cast/box.rs @@ -12,8 +12,6 @@ use std::any::type_name; -use error_stack::report; - use crate::libs::intertrait::cast::error::CastError; use crate::libs::intertrait::{caster, CastFrom}; @@ -22,7 +20,7 @@ pub trait CastBox /// Casts a box to this trait into that of type `OtherTrait`. fn cast( self: Box, - ) -> error_stack::Result, CastError>; + ) -> Result, CastError>; } /// A blanket implementation of `CastBox` for traits extending `CastFrom`. @@ -30,15 +28,14 @@ impl CastBox for CastFromSelf { fn cast( self: Box, - ) -> error_stack::Result, CastError> + ) -> Result, CastError> { match caster::((*self).type_id()) { Some(caster) => Ok((caster.cast_box)(self.box_any())), - None => Err(report!(CastError).attach_printable(format!( - "From {} to {}", - type_name::(), - type_name::() - ))), + None => Err(CastError::CastFailed { + from: type_name::(), + to: type_name::(), + }), } } } diff --git a/src/libs/intertrait/cast/error.rs b/src/libs/intertrait/cast/error.rs index e4211b1..74eb3ca 100644 --- a/src/libs/intertrait/cast/error.rs +++ b/src/libs/intertrait/cast/error.rs @@ -1,17 +1,10 @@ -use std::fmt; -use std::fmt::{Display, Formatter}; - -use error_stack::Context; - -#[derive(Debug)] -pub struct CastError; - -impl Display for CastError +#[derive(thiserror::Error, Debug)] +pub enum CastError { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result + #[error("Failed to cast from trait {from} to trait {to}")] + CastFailed { - fmt.write_str("Failed to cast between traits") - } + from: &'static str, + to: &'static str, + }, } - -impl Context for CastError {} diff --git a/src/libs/intertrait/cast/rc.rs b/src/libs/intertrait/cast/rc.rs index 6cd377e..dfb71c2 100644 --- a/src/libs/intertrait/cast/rc.rs +++ b/src/libs/intertrait/cast/rc.rs @@ -12,8 +12,6 @@ use std::any::type_name; use std::rc::Rc; -use error_stack::report; - use crate::libs::intertrait::cast::error::CastError; use crate::libs::intertrait::{caster, CastFrom}; @@ -22,7 +20,7 @@ pub trait CastRc /// Casts an `Rc` for this trait into that for type `OtherTrait`. fn cast( self: Rc, - ) -> error_stack::Result, CastError>; + ) -> Result, CastError>; } /// A blanket implementation of `CastRc` for traits extending `CastFrom`. @@ -30,15 +28,14 @@ impl CastRc for CastFromSelf { fn cast( self: Rc, - ) -> error_stack::Result, CastError> + ) -> Result, CastError> { match caster::((*self).type_id()) { Some(caster) => Ok((caster.cast_rc)(self.rc_any())), - None => Err(report!(CastError).attach_printable(format!( - "From {} to {}", - type_name::(), - type_name::() - ))), + None => Err(CastError::CastFailed { + from: type_name::(), + to: type_name::(), + }), } } } diff --git a/src/libs/mod.rs b/src/libs/mod.rs index 034d11d..8d5583d 100644 --- a/src/libs/mod.rs +++ b/src/libs/mod.rs @@ -1,4 +1,3 @@ pub mod intertrait; -pub extern crate error_stack; pub extern crate linkme; diff --git a/src/provider.rs b/src/provider.rs index e12a12a..ad94589 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -1,12 +1,13 @@ #![allow(clippy::module_name_repetitions)] use std::marker::PhantomData; -use crate::errors::injectable::ResolveError; +use crate::errors::injectable::InjectableError; use crate::interfaces::any_factory::AnyFactory; use crate::interfaces::injectable::Injectable; use crate::ptr::{FactoryPtr, SingletonPtr, TransientPtr}; use crate::DIContainer; +#[derive(strum_macros::Display, Debug)] pub enum Providable { Transient(TransientPtr), @@ -21,7 +22,7 @@ pub trait IProvider &self, di_container: &DIContainer, dependency_history: Vec<&'static str>, - ) -> error_stack::Result; + ) -> Result; } pub struct TransientTypeProvider @@ -51,7 +52,7 @@ where &self, di_container: &DIContainer, dependency_history: Vec<&'static str>, - ) -> error_stack::Result + ) -> Result { Ok(Providable::Transient(InjectableType::resolve( di_container, @@ -85,7 +86,7 @@ where &self, _di_container: &DIContainer, _dependency_history: Vec<&'static str>, - ) -> error_stack::Result + ) -> Result { Ok(Providable::Singleton(self.singleton.clone())) } @@ -113,7 +114,7 @@ impl IProvider for FactoryProvider &self, _di_container: &DIContainer, _dependency_history: Vec<&'static str>, - ) -> error_stack::Result + ) -> Result { Ok(Providable::Factory(self.factory.clone())) } -- cgit v1.2.3-18-g5258