use std::any::{Any, TypeId};
use std::fmt;
use std::sync::Arc;
use super::{Registry, Result};
pub trait Resolve<S>: Clone + Send + Sync + Sized + 'static {
fn dependencies(into: &mut Vec<TypeId>);
fn resolve(registry: &Registry<S>) -> Result<Self>;
}
#[derive(Debug)]
pub struct MissingDependency {
dependency: &'static str,
}
impl MissingDependency {
pub fn dependency(&self) -> &'static str {
self.dependency
}
}
impl fmt::Display for MissingDependency {
fn fmt(
&self,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
write!(f, "`{}` is not registered", self.dependency)
}
}
impl std::error::Error for MissingDependency {}
impl<S: 'static> Resolve<S> for () {
fn dependencies(_: &mut Vec<TypeId>) {}
fn resolve(_: &Registry<S>) -> Result<Self> {
Ok(())
}
}
impl<S: 'static, T: Any + Send + Sync> Resolve<S> for Arc<T> {
fn dependencies(into: &mut Vec<TypeId>) {
into.push(TypeId::of::<T>());
}
fn resolve(registry: &Registry<S>) -> Result<Self> {
registry.resolve::<T>().ok_or_else(|| {
MissingDependency { dependency: std::any::type_name::<T>() }.into()
})
}
}
impl<S: 'static, T: Any + Send + Sync> Resolve<S> for Option<Arc<T>> {
fn dependencies(into: &mut Vec<TypeId>) {
into.push(TypeId::of::<T>());
}
fn resolve(registry: &Registry<S>) -> Result<Self> {
Ok(registry.resolve::<T>())
}
}
macro_rules! resolve_tuple {
($($member:ident),+) => {
impl<S: 'static, $($member: Resolve<S>),+> Resolve<S> for ($($member,)+) {
fn dependencies(into: &mut Vec<TypeId>) {
$($member::dependencies(into);)+
}
fn resolve(registry: &Registry<S>) -> Result<Self> {
Ok(($($member::resolve(registry)?,)+))
}
}
};
}
resolve_tuple!(A);
resolve_tuple!(A, B);
resolve_tuple!(A, B, C);
resolve_tuple!(A, B, C, D);
resolve_tuple!(A, B, C, D, E);
resolve_tuple!(A, B, C, D, E, F);
resolve_tuple!(A, B, C, D, E, F, G);
resolve_tuple!(A, B, C, D, E, F, G, H);