aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml4
-rw-r--r--examples/unbound/animal_store.rs34
-rw-r--r--examples/unbound/animals/human.rs20
-rw-r--r--examples/unbound/bootstrap.rs7
-rw-r--r--examples/unbound/interfaces/animal_store.rs11
-rw-r--r--examples/unbound/interfaces/mod.rs1
-rw-r--r--examples/unbound/main.rs9
-rw-r--r--examples/with-3rd-party/bootstrap.rs5
-rw-r--r--examples/with-3rd-party/main.rs25
-rw-r--r--macros/src/injectable_impl.rs39
-rw-r--r--src/di_container.rs134
-rw-r--r--src/di_container_binding_map.rs10
-rw-r--r--src/errors/di_container.rs75
-rw-r--r--src/errors/injectable.rs41
-rw-r--r--src/interfaces/any_factory.rs10
-rw-r--r--src/interfaces/injectable.rs14
-rw-r--r--src/libs/intertrait/cast/arc.rs15
-rw-r--r--src/libs/intertrait/cast/box.rs15
-rw-r--r--src/libs/intertrait/cast/error.rs21
-rw-r--r--src/libs/intertrait/cast/rc.rs15
-rw-r--r--src/libs/mod.rs1
-rw-r--r--src/provider.rs11
22 files changed, 281 insertions, 236 deletions
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<dyn IDog>,
+ cat: TransientPtr<dyn ICat>,
+}
+
+#[injectable]
+impl AnimalStore
+{
+ fn new(dog: SingletonPtr<dyn IDog>, cat: TransientPtr<dyn ICat>) -> Self
+ {
+ Self { dog, cat }
+ }
+}
+
+impl IAnimalStore for AnimalStore
+{
+ fn get_dog(&self) -> SingletonPtr<dyn IDog>
+ {
+ self.dog.clone()
+ }
+
+ fn get_cat(&self) -> &TransientPtr<dyn ICat>
+ {
+ &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<dyn IDog>,
- cat: TransientPtr<dyn ICat>,
+ animal_store: TransientPtr<dyn IAnimalStore>,
}
#[injectable(IHuman)]
impl Human
{
- pub fn new(dog: SingletonPtr<dyn IDog>, cat: TransientPtr<dyn ICat>) -> Self
+ pub fn new(animal_store: TransientPtr<dyn IAnimalStore>) -> 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;
@@ -20,4 +22,9 @@ pub fn bootstrap() -> DIContainer
di_container.bind::<dyn IHuman>().to::<Human>().unwrap();
di_container
+ .bind::<dyn IAnimalStore>()
+ .to::<AnimalStore>()
+ .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<dyn IDog>;
+
+ fn get_cat(&self) -> &TransientPtr<dyn ICat>;
+}
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<dyn Error>>
{
println!("Hello, world!");
@@ -20,7 +23,9 @@ fn main()
dog.woof();
- let human = di_container.get::<dyn IHuman>().unwrap();
+ let human = di_container.get::<dyn IHuman>()?;
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<DIContainer, BindingBuilderError>
+pub fn bootstrap() -> Result<DIContainer, Box<dyn Error>>
{
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<dyn Error>>
{
println!("Hello, world!");
- let di_container = bootstrap().change_context(ApplicationError)?;
+ let di_container = bootstrap()?;
- let ninja = di_container
- .get::<dyn INinja>()
- .change_context(ApplicationError)?;
+ let ninja = di_container.get::<dyn INinja>()?;
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<Self>,
- 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<Interface>(err: Report<CastError>) -> Report<DIContainerError>
-where
- Interface: 'static + ?Sized,
-{
- err.change_context(DIContainerError)
- .attach_printable(format!(
- "Unable to cast binding for interface '{}'",
- type_name::<Interface>()
- ))
-}
-
/// 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<Implementation>(&mut self) -> error_stack::Result<(), BindingBuilderError>
+ pub fn to<Implementation>(&mut self) -> Result<(), BindingBuilderError>
where
Implementation: Injectable,
{
@@ -108,10 +94,7 @@ where
.bindings
.set::<Interface>(Box::new(TransientTypeProvider::<Implementation>::new()))
.ok_or_else(|| {
- report!(BindingBuilderError).attach_printable(format!(
- "Binding already exists for interface '{}'",
- type_name::<Interface>()
- ))
+ BindingBuilderError::BindingAlreadyExists(type_name::<Interface>())
})?;
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<Implementation>(
- &mut self,
- ) -> error_stack::Result<(), BindingBuilderError>
+ pub fn to_singleton<Implementation>(&mut self) -> Result<(), BindingBuilderError>
where
Implementation: Injectable,
{
let singleton: SingletonPtr<Implementation> = SingletonPtr::from(
Implementation::resolve(self.di_container, Vec::new())
- .change_context(BindingBuilderError)?,
+ .map_err(BindingBuilderError::SingletonResolveFailed)?,
);
self.di_container
.bindings
.set::<Interface>(Box::new(SingletonProvider::new(singleton)))
.ok_or_else(|| {
- report!(BindingBuilderError).attach_printable(format!(
- "Binding already exists for interface '{}'",
- type_name::<Interface>()
- ))
+ BindingBuilderError::BindingAlreadyExists(type_name::<Interface>())
})?;
Ok(())
@@ -159,7 +137,7 @@ where
pub fn to_factory<Args, Return>(
&mut self,
factory_func: &'static dyn Fn<Args, Output = TransientPtr<Return>>,
- ) -> 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::<Interface>()
- ))
+ BindingBuilderError::BindingAlreadyExists(type_name::<Interface>())
})?;
Ok(())
@@ -194,7 +169,7 @@ where
pub fn to_default_factory<Return>(
&mut self,
factory_func: &'static dyn Fn<(), Output = TransientPtr<Return>>,
- ) -> 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::<Interface>()
- ))
+ BindingBuilderError::BindingAlreadyExists(type_name::<Interface>())
})?;
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<Interface>(
- &self,
- ) -> error_stack::Result<TransientPtr<Interface>, DIContainerError>
+ pub fn get<Interface>(&self) -> Result<TransientPtr<Interface>, DIContainerError>
where
Interface: 'static + ?Sized,
{
@@ -268,7 +238,7 @@ impl DIContainer
/// - The binding for `Interface` is not a singleton
pub fn get_singleton<Interface>(
&self,
- ) -> error_stack::Result<SingletonPtr<Interface>, DIContainerError>
+ ) -> Result<SingletonPtr<Interface>, DIContainerError>
where
Interface: 'static + ?Sized,
{
@@ -288,7 +258,7 @@ impl DIContainer
#[cfg(feature = "factory")]
pub fn get_factory<Interface>(
&self,
- ) -> error_stack::Result<crate::ptr::FactoryPtr<Interface>, DIContainerError>
+ ) -> Result<crate::ptr::FactoryPtr<Interface>, DIContainerError>
where
Interface: 'static + ?Sized,
{
@@ -297,20 +267,21 @@ impl DIContainer
if let Providable::Factory(binding_factory) = binding_providable {
return binding_factory
.cast::<Interface>()
- .map_err(unable_to_cast_binding::<Interface>);
+ .map_err(|_| DIContainerError::CastFailed(type_name::<Interface>()));
}
- Err(report!(DIContainerError).attach_printable(format!(
- "Binding for interface '{}' is not a factory",
- type_name::<Interface>()
- )))
+ Err(DIContainerError::WrongBindingType {
+ interface: type_name::<Interface>(),
+ expected: "factory",
+ found: binding_providable.to_string().to_lowercase(),
+ })
}
#[doc(hidden)]
pub fn get_with_history<Interface>(
&self,
dependency_history: Vec<&'static str>,
- ) -> error_stack::Result<TransientPtr<Interface>, DIContainerError>
+ ) -> Result<TransientPtr<Interface>, DIContainerError>
where
Interface: 'static + ?Sized,
{
@@ -320,7 +291,7 @@ impl DIContainer
if let Providable::Transient(binding_transient) = binding_providable {
return binding_transient
.cast::<Interface>()
- .map_err(unable_to_cast_binding::<Interface>);
+ .map_err(|_| DIContainerError::CastFailed(type_name::<Interface>()));
}
#[cfg(feature = "factory")]
@@ -329,22 +300,23 @@ impl DIContainer
let factory = binding_factory
.cast::<dyn IFactory<(), Interface>>()
- .map_err(unable_to_cast_binding::<Interface>)?;
+ .map_err(|_| DIContainerError::CastFailed(type_name::<Interface>()))?;
return Ok(factory());
}
- Err(report!(DIContainerError).attach_printable(format!(
- "Binding for interface '{}' is not transient",
- type_name::<Interface>()
- )))
+ Err(DIContainerError::WrongBindingType {
+ interface: type_name::<Interface>(),
+ expected: "transient",
+ found: binding_providable.to_string().to_lowercase(),
+ })
}
#[doc(hidden)]
pub fn get_singleton_with_history<Interface>(
&self,
dependency_history: Vec<&'static str>,
- ) -> error_stack::Result<SingletonPtr<Interface>, DIContainerError>
+ ) -> Result<SingletonPtr<Interface>, DIContainerError>
where
Interface: 'static + ?Sized,
{
@@ -354,30 +326,30 @@ impl DIContainer
if let Providable::Singleton(binding_singleton) = binding_providable {
return binding_singleton
.cast::<Interface>()
- .map_err(unable_to_cast_binding::<Interface>);
+ .map_err(|_| DIContainerError::CastFailed(type_name::<Interface>()));
}
- Err(report!(DIContainerError).attach_printable(format!(
- "Binding for interface '{}' is not a singleton",
- type_name::<Interface>()
- )))
+ Err(DIContainerError::WrongBindingType {
+ interface: type_name::<Interface>(),
+ expected: "singleton",
+ found: binding_providable.to_string().to_lowercase(),
+ })
}
fn get_binding_providable<Interface>(
&self,
dependency_history: Vec<&'static str>,
- ) -> error_stack::Result<Providable, DIContainerError>
+ ) -> Result<Providable, DIContainerError>
where
Interface: 'static + ?Sized,
{
self.bindings
.get::<Interface>()?
.provide(self, dependency_history)
- .change_context(DIContainerError)
- .attach_printable(format!(
- "Failed to resolve binding for interface '{}'",
- type_name::<Interface>()
- ))
+ .map_err(|err| DIContainerError::BindingResolveFailed {
+ reason: err,
+ interface: type_name::<Interface>(),
+ })
}
}
@@ -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<Self>,
- crate::errors::injectable::ResolveError,
- >
+ ) -> Result<TransientPtr<Self>, 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<Self>,
- crate::errors::injectable::ResolveError,
- >
+ ) -> Result<TransientPtr<Self>, 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<Providable, ResolveError>;
+ ) -> Result<Providable, InjectableError>;
}
}
@@ -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<Providable, ResolveError>;
+ ) -> Result<Providable, InjectableError>;
}
}
@@ -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<Providable, ResolveError>;
+ ) -> Result<Providable, InjectableError>;
}
}
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<Interface>(&self) -> error_stack::Result<&dyn IProvider, DIContainerError>
+ pub fn get<Interface>(&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::<Interface>()
- ))
- })?
+ .ok_or_else(|| DIContainerError::BindingNotFound(type_name::<Interface>()))?
.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<DIContainerError>,
-/// 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<TransientPtr<Self>, ResolveError>
+ ) -> Result<TransientPtr<Self>, 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<OtherTrait: ?Sized + 'static>(
self: Arc<Self>,
- ) -> error_stack::Result<Arc<OtherTrait>, CastError>;
+ ) -> Result<Arc<OtherTrait>, CastError>;
}
/// A blanket implementation of `CastArc` for traits extending `CastFrom`, `Sync`, and `Send`.
@@ -30,15 +28,14 @@ impl<CastFromSelf: ?Sized + CastFromSync> CastArc for CastFromSelf
{
fn cast<OtherTrait: ?Sized + 'static>(
self: Arc<Self>,
- ) -> error_stack::Result<Arc<OtherTrait>, CastError>
+ ) -> Result<Arc<OtherTrait>, CastError>
{
match caster::<OtherTrait>((*self).type_id()) {
Some(caster) => Ok((caster.cast_arc)(self.arc_any())),
- None => Err(report!(CastError).attach_printable(format!(
- "From {} to {}",
- type_name::<CastFromSelf>(),
- type_name::<OtherTrait>()
- ))),
+ None => Err(CastError::CastFailed {
+ from: type_name::<CastFromSelf>(),
+ to: type_name::<OtherTrait>(),
+ }),
}
}
}
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<OtherTrait: ?Sized + 'static>(
self: Box<Self>,
- ) -> error_stack::Result<Box<OtherTrait>, CastError>;
+ ) -> Result<Box<OtherTrait>, CastError>;
}
/// A blanket implementation of `CastBox` for traits extending `CastFrom`.
@@ -30,15 +28,14 @@ impl<CastFromSelf: ?Sized + CastFrom> CastBox for CastFromSelf
{
fn cast<OtherTrait: ?Sized + 'static>(
self: Box<Self>,
- ) -> error_stack::Result<Box<OtherTrait>, CastError>
+ ) -> Result<Box<OtherTrait>, CastError>
{
match caster::<OtherTrait>((*self).type_id()) {
Some(caster) => Ok((caster.cast_box)(self.box_any())),
- None => Err(report!(CastError).attach_printable(format!(
- "From {} to {}",
- type_name::<CastFromSelf>(),
- type_name::<OtherTrait>()
- ))),
+ None => Err(CastError::CastFailed {
+ from: type_name::<CastFromSelf>(),
+ to: type_name::<OtherTrait>(),
+ }),
}
}
}
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<OtherTrait: ?Sized + 'static>(
self: Rc<Self>,
- ) -> error_stack::Result<Rc<OtherTrait>, CastError>;
+ ) -> Result<Rc<OtherTrait>, CastError>;
}
/// A blanket implementation of `CastRc` for traits extending `CastFrom`.
@@ -30,15 +28,14 @@ impl<CastFromSelf: ?Sized + CastFrom> CastRc for CastFromSelf
{
fn cast<OtherTrait: ?Sized + 'static>(
self: Rc<Self>,
- ) -> error_stack::Result<Rc<OtherTrait>, CastError>
+ ) -> Result<Rc<OtherTrait>, CastError>
{
match caster::<OtherTrait>((*self).type_id()) {
Some(caster) => Ok((caster.cast_rc)(self.rc_any())),
- None => Err(report!(CastError).attach_printable(format!(
- "From {} to {}",
- type_name::<CastFromSelf>(),
- type_name::<OtherTrait>()
- ))),
+ None => Err(CastError::CastFailed {
+ from: type_name::<CastFromSelf>(),
+ to: type_name::<OtherTrait>(),
+ }),
}
}
}
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<dyn Injectable>),
@@ -21,7 +22,7 @@ pub trait IProvider
&self,
di_container: &DIContainer,
dependency_history: Vec<&'static str>,
- ) -> error_stack::Result<Providable, ResolveError>;
+ ) -> Result<Providable, InjectableError>;
}
pub struct TransientTypeProvider<InjectableType>
@@ -51,7 +52,7 @@ where
&self,
di_container: &DIContainer,
dependency_history: Vec<&'static str>,
- ) -> error_stack::Result<Providable, ResolveError>
+ ) -> Result<Providable, InjectableError>
{
Ok(Providable::Transient(InjectableType::resolve(
di_container,
@@ -85,7 +86,7 @@ where
&self,
_di_container: &DIContainer,
_dependency_history: Vec<&'static str>,
- ) -> error_stack::Result<Providable, ResolveError>
+ ) -> Result<Providable, InjectableError>
{
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<Providable, ResolveError>
+ ) -> Result<Providable, InjectableError>
{
Ok(Providable::Factory(self.factory.clone()))
}