use std::marker::PhantomData;
use std::sync::Arc;
use crate::injection_context::InjectionContext;
use crate::{Catalog, InjectionError};
pub trait DependencySpec {
type IfaceType: ?Sized;
type ReturnType;
fn get(cat: &Catalog, ctx: &InjectionContext) -> Result<Self::ReturnType, InjectionError>;
}
pub struct OneOf<Iface>
where
Iface: 'static + ?Sized + Send + Sync,
{
_dummy: PhantomData<Iface>,
}
impl<Iface> DependencySpec for OneOf<Iface>
where
Iface: 'static + ?Sized + Send + Sync,
{
type IfaceType = Iface;
type ReturnType = Arc<Iface>;
fn get(cat: &Catalog, ctx: &InjectionContext) -> Result<Self::ReturnType, InjectionError> {
let mut builders = cat.builders_for::<Iface>();
if let Some(first) = builders.next() {
if builders.next().is_some() {
Err(InjectionError::ambiguous::<Iface>(ctx))
} else {
first.get_with_context(cat, ctx)
}
} else {
Err(InjectionError::unregistered::<Iface>(ctx))
}
}
}
pub struct AllOf<Iface>
where
Iface: 'static + ?Sized,
{
_dummy: PhantomData<Iface>,
}
impl<Iface> DependencySpec for AllOf<Iface>
where
Iface: 'static + ?Sized,
{
type IfaceType = Iface;
type ReturnType = Vec<Arc<Iface>>;
fn get(cat: &Catalog, ctx: &InjectionContext) -> Result<Self::ReturnType, InjectionError> {
cat.builders_for::<Iface>()
.map(|b| b.get_with_context(cat, ctx))
.collect()
}
}
pub struct Maybe<Inner: DependencySpec + 'static> {
_dummy: PhantomData<Inner>,
}
impl<Inner: DependencySpec + 'static> DependencySpec for Maybe<Inner> {
type IfaceType = Inner::IfaceType;
type ReturnType = Option<Inner::ReturnType>;
fn get(cat: &Catalog, ctx: &InjectionContext) -> Result<Self::ReturnType, InjectionError> {
match Inner::get(cat, ctx) {
Ok(v) => Ok(Some(v)),
Err(InjectionError::Unregistered(_)) => Ok(None),
Err(err) => Err(err),
}
}
}
pub struct Lazy<Inner: DependencySpec + 'static> {
_dummy: PhantomData<Inner>,
}
impl<Inner: DependencySpec + 'static> DependencySpec for Lazy<Inner> {
type IfaceType = Inner::IfaceType;
type ReturnType = crate::lazy::Lazy<Inner::ReturnType>;
#[cfg(not(feature = "tokio"))]
fn get(cat: &Catalog, _ctx: &InjectionContext) -> Result<Self::ReturnType, InjectionError> {
let cat = cat.clone();
Ok(crate::lazy::Lazy::new(move || cat.get::<Inner>()))
}
#[cfg(feature = "tokio")]
fn get(cat: &Catalog, _ctx: &InjectionContext) -> Result<Self::ReturnType, InjectionError> {
let fallback_cat = cat.clone();
Ok(crate::lazy::Lazy::new(
move || match crate::catalog::CURRENT_CATALOG.try_with(|cat| cat.get::<Inner>()) {
Ok(v) => v,
Err(_) => fallback_cat.get::<Inner>(),
},
))
}
}