use crate::builder::ServicesBuilder;
use crate::builder::{BindingKind, BindingLifetime};
use crate::either_iter::EitherIter;
use crate::mbmany::OneOrMany;
use crate::resolver::Error;
use crate::resolver::graph;
use crate::resolver::resolved::Resolved;
use crate::runtime::ServiceFactory;
use crate::runtime::TypeMeta;
use crate::runtime::{ErasedArc, ErasedUnsizer};
use std::collections::HashMap;
use std::iter;
#[derive(Debug)]
pub struct Services {
services: HashMap<TypeMeta, ImmutableBinding>,
}
#[derive(Debug)]
enum ImmutableBinding {
Type {
binding: ImmutableTypeBinding,
},
Alias {
impls: OneOrMany<(ErasedUnsizer, ImmutableTypeBinding)>,
},
}
impl ImmutableBinding {
pub fn unwrap_type(&self) -> &ImmutableTypeBinding {
match self {
ImmutableBinding::Type { binding } => binding,
ImmutableBinding::Alias { .. } => {
panic!("Called unwrap_type on an Alias binding")
}
}
}
}
#[derive(Debug, Clone)]
enum ImmutableTypeBinding {
Singleton(ErasedArc),
Transient(ServiceFactory),
}
impl ImmutableTypeBinding {
fn from(value: BindingLifetime, services: &Services) -> Result<Self, Error> {
let binding = match value {
BindingLifetime::Singleton(x) => Self::Singleton(x.to_instance(services)?),
BindingLifetime::Transient(x) => Self::Transient(x),
};
Ok(binding)
}
}
impl Services {
pub fn from_builder(builder: ServicesBuilder) -> Result<Self, Error> {
let bindings = builder.to_vec();
let bindings = graph::merge_aliases(bindings);
let bindings = graph::resolve_order(bindings)?;
let unbind: Vec<_> = bindings
.iter()
.filter_map(|x| match x.kind {
BindingKind::Type { bind_self, .. } if !bind_self => Some(x.ty),
_ => None,
})
.collect();
let mut services = Self {
services: HashMap::new(),
};
for binding in bindings {
let ty = binding.ty;
let binding = match binding.kind {
BindingKind::Type { lifetime, .. } => ImmutableBinding::Type {
binding: ImmutableTypeBinding::from(lifetime, &services)?,
},
BindingKind::Alias { impls } => {
ImmutableBinding::Alias {
impls: impls
.iter()
.map(|(meta, unsizer)| {
let binding = services.services.get(meta).unwrap();
(unsizer.clone(), binding.unwrap_type().clone())
})
.collect(),
}
}
};
services.services.insert(ty, binding);
}
for ty in unbind {
services.services.remove(&ty);
}
Ok(services)
}
}
impl Services {
pub fn resolve_all<T>(&self) -> Option<impl DoubleEndedIterator<Item = Resolved<T>>>
where
T: ?Sized + Send + Sync + 'static,
{
let type_meta = TypeMeta::of::<T>();
self.services.get(&type_meta).map(|x| match x {
ImmutableBinding::Type { binding } => {
let iter = iter::once(binding).map(|binding| {
self.get_instance(binding)
.coerce::<T>()
.expect("Failed to coerce. This is a bug!")
});
EitherIter::Left(iter)
}
ImmutableBinding::Alias { impls } => {
let iter = impls.into_iter().map(|(unsizer, binding)| {
let arc = self.get_instance(binding);
unsizer
.unsize::<T>(arc)
.expect("Failed to unsize. This is a bug!")
});
EitherIter::Right(iter)
}
})
}
pub fn resolve<T>(&self) -> Option<Resolved<T>>
where
T: ?Sized + Send + Sync + 'static,
{
self.resolve_all().map(|mut x| x.next_back().unwrap())
}
fn get_instance(&self, binding: &ImmutableTypeBinding) -> ErasedArc {
match binding {
ImmutableTypeBinding::Singleton(arc) => arc.clone(),
ImmutableTypeBinding::Transient(factory) => factory
.produce(self)
.expect("Failed while trying to instantiate Transient"),
}
}
}