use crate::container::{
Container, ConvertContainer, InstanceContainer, SingletonContainer, TransientContainer,
};
use crate::index::{ParentIndex, SelfIndex};
use frunk::hlist::{HList, Selector};
use frunk::{HCons, HNil};
use std::ops::Deref;
use std::rc::Rc;
use std::sync::Arc;
#[derive(Debug)]
pub struct ServiceProvider<Parent, Conts> {
parent: Parent,
containers: Conts,
}
#[derive(Debug)]
pub struct EmptyServiceProvider;
impl ServiceProvider<EmptyServiceProvider, HNil> {
pub fn new() -> Self {
ServiceProvider {
parent: EmptyServiceProvider,
containers: HNil,
}
}
}
impl Default for ServiceProvider<EmptyServiceProvider, HNil> {
fn default() -> Self {
Self::new()
}
}
impl<Parent, Conts> ServiceProvider<Parent, Conts> {
pub(crate) fn dependencies(&self) -> &Conts {
&self.containers
}
pub fn fork(&self) -> ServiceProvider<&Self, HNil> {
ServiceProvider {
parent: self,
containers: HNil,
}
}
pub fn fork_rc(self: &Rc<ServiceProvider<Parent, Conts>>) -> ServiceProvider<Rc<Self>, HNil> {
ServiceProvider {
parent: self.clone(),
containers: HNil,
}
}
pub fn fork_arc(
self: &Arc<ServiceProvider<Parent, Conts>>,
) -> ServiceProvider<Arc<Self>, HNil> {
ServiceProvider {
parent: self.clone(),
containers: HNil,
}
}
}
type ContainerTransientAddConvert<Parent, T, U, Conts> =
ServiceProvider<Parent, HCons<ConvertContainer<TransientContainer<T>, T, U>, Conts>>;
type ContainerSingletonAddConvert<Parent, T, U, Conts> =
ServiceProvider<Parent, HCons<ConvertContainer<SingletonContainer<T>, T, U>, Conts>>;
type ContainerInstanceAddConvert<Parent, T, U, Conts> =
ServiceProvider<Parent, HCons<ConvertContainer<InstanceContainer<T>, T, U>, Conts>>;
impl<Parent, Conts: HList> ServiceProvider<Parent, Conts> {
pub fn _add<Cont: Container>(
self,
data: Cont::Data,
) -> ServiceProvider<Parent, HCons<Cont, Conts>> {
let ServiceProvider { parent, containers } = self;
ServiceProvider {
parent,
containers: containers.prepend(Container::init(data)),
}
}
pub fn add_transient<T>(self) -> ServiceProvider<Parent, HCons<TransientContainer<T>, Conts>>
where
TransientContainer<T>: Container<Data = ()>,
{
self._add::<TransientContainer<T>>(())
}
pub fn add_singleton<T>(self) -> ServiceProvider<Parent, HCons<SingletonContainer<T>, Conts>>
where
SingletonContainer<T>: Container<Data = ()>,
{
self._add::<SingletonContainer<T>>(())
}
pub fn add_instance<T>(
self,
data: T,
) -> ServiceProvider<Parent, HCons<InstanceContainer<T>, Conts>>
where
InstanceContainer<T>: Container<Data = T>,
{
self._add::<InstanceContainer<T>>(data)
}
pub fn add_transient_c<U, T>(self) -> ContainerTransientAddConvert<Parent, T, U, Conts>
where
T: Into<U>,
ConvertContainer<TransientContainer<T>, T, U>: Container<Data = ()>,
TransientContainer<T>: Container<Data = ()>,
{
self._add::<ConvertContainer<TransientContainer<T>, T, U>>(())
}
pub fn add_singleton_c<U, T>(self) -> ContainerSingletonAddConvert<Parent, T, U, Conts>
where
T: Into<U>,
ConvertContainer<SingletonContainer<T>, T, U>: Container<Data = ()>,
SingletonContainer<T>: Container<Data = ()>,
{
self._add::<ConvertContainer<SingletonContainer<T>, T, U>>(())
}
pub fn add_instance_c<U, T>(
self,
instance: T,
) -> ContainerInstanceAddConvert<Parent, T, U, Conts>
where
T: Into<U>,
ConvertContainer<InstanceContainer<T>, T, U>: Container<Data = T>,
InstanceContainer<T>: Container<Data = T>,
{
self._add::<ConvertContainer<InstanceContainer<T>, T, U>>(instance)
}
}
impl<Parent, Conts, T, Index> Selector<T, SelfIndex<Index>> for ServiceProvider<Parent, Conts>
where
Conts: Selector<T, Index>,
{
fn get(&self) -> &T {
self.dependencies().get()
}
fn get_mut(&mut self) -> &mut T {
unreachable!()
}
}
impl<Parent, Conts, T, Index> Selector<T, ParentIndex<Index>> for ServiceProvider<Parent, Conts>
where
Parent: Deref,
Parent::Target: Selector<T, Index>,
{
fn get(&self) -> &T {
self.parent.deref().get()
}
fn get_mut(&mut self) -> &mut T {
unreachable!()
}
}