use std::sync::Arc;
use crate::container::Container;
use crate::error::Result;
pub trait Factory<T, Deps = ()>: Clone + Send + Sync + Sized + 'static {
fn create<C: Container>(self, registry: &C) -> Result<T>;
}
pub struct BoxedFactory<F, T, Deps> {
pub factory: F,
_marker: std::marker::PhantomData<fn(Deps) -> T>,
}
impl<F, T, Deps> BoxedFactory<F, T, Deps> {
pub fn new(factory: F) -> Self {
Self {
factory,
_marker: std::marker::PhantomData,
}
}
}
impl<F, T, Deps> Clone for BoxedFactory<F, T, Deps>
where
F: Clone,
{
fn clone(&self) -> Self {
Self {
factory: self.factory.clone(),
_marker: std::marker::PhantomData,
}
}
}
impl<T, F> Factory<T, ()> for F
where
F: FnOnce() -> T + Clone + Send + Sync + 'static,
T: 'static,
{
fn create<C: Container>(self, _: &C) -> Result<T> {
Ok(self())
}
}
mod private {
pub enum FactoryMarker {}
pub enum ValueFactoryMarker {}
pub trait Mark<M = FactoryMarker> {}
impl<T> Mark<FactoryMarker> for T where T: 'static {}
}
macro_rules! impl_resolvable {
([$($ty:ident),*], $last:ident) => {
impl<T, F, M, $($ty,)* $last> Factory<T, (M, $($ty,)* $last)> for F
where
F: FnOnce($(Arc<$ty>,)* Arc<$last>) -> T + Clone + Send + Sync + 'static,
$($ty: 'static,)*
$last: 'static + private::Mark<M>,
{
#[allow(non_snake_case)]
fn create<C: Container>(self, registry: &C) -> Result<T> {
use crate::error::TypedError;
$(
let $ty = registry.get::<$ty>()
.map_err(|source| {
super::error::DependencyResolutionFailed::error_with_source(
format!(
"Failed to resolve dependency '{}' for type '{}'",
std::any::type_name::<$ty>(),
std::any::type_name::<T>()
),
source
)
})?;
)*
let $last = registry.get::<$last>()
.map_err(|source| {
super::error::DependencyResolutionFailed::error_with_source(
format!(
"Failed to resolve dependency '{}' for type '{}'",
std::any::type_name::<$last>(),
std::any::type_name::<T>()
),
source
)
})?;
Ok(self($($ty,)* $last))
}
}
};
}
all_the_tuples!(impl_resolvable);
#[derive(Clone)]
pub struct Value<T>(pub T);
pub trait ValueFactory<T> {
fn into_value(self) -> T;
}
impl<T> ValueFactory<T> for Value<T>
where
T: Clone,
{
#[inline(always)]
fn into_value(self) -> T {
self.0
}
}
impl<V, T> Factory<T, private::ValueFactoryMarker> for V
where
V: ValueFactory<T> + Clone + Send + Sync + 'static,
{
fn create<C: Container>(self, _: &C) -> Result<T> {
Ok(self.into_value())
}
}