dill 0.15.0

Runtime depenency injection library.
Documentation
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

use crate::{Builder, DependencySpec, TypeInfo};

pub struct InjectionContext<'a> {
    pub frame: Option<InjectionStackFrame>,
    pub prev: Option<&'a InjectionContext<'a>>,
}

impl<'a> InjectionContext<'a> {
    pub fn new_root() -> InjectionContext<'static> {
        InjectionContext {
            frame: None,
            prev: None,
        }
    }

    pub fn push(&'a self, frame: InjectionStackFrame) -> InjectionContext<'a> {
        InjectionContext {
            frame: Some(frame),
            prev: Some(self),
        }
    }

    pub fn push_resolve<Spec: DependencySpec + 'static>(&'a self) -> InjectionContext<'a> {
        self.push(InjectionStackFrame::Resolve {
            iface: TypeInfo::of::<Spec::IfaceType>(),
            spec: TypeInfo::of::<Spec>(),
        })
    }

    pub fn push_build(&'a self, b: &dyn Builder) -> InjectionContext<'a> {
        self.push(InjectionStackFrame::Build {
            instance: b.instance_type(),
            scope: b.scope_type(),
        })
    }

    pub fn to_stack(&self) -> InjectionStack {
        let mut stack = InjectionStack { frames: Vec::new() };
        let mut current = Some(self);
        while let Some(c) = current {
            if let Some(f) = &c.frame {
                stack.frames.push(f.clone());
            }
            current = c.prev;
        }
        stack
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[derive(Clone, Debug)]
pub struct InjectionStack {
    pub frames: Vec<InjectionStackFrame>,
}

#[derive(Clone, Debug)]
pub enum InjectionStackFrame {
    Resolve { iface: TypeInfo, spec: TypeInfo },
    Build { instance: TypeInfo, scope: TypeInfo },
}

impl std::fmt::Display for InjectionStack {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for (line, frame) in self.frames.iter().rev().enumerate() {
            match frame {
                InjectionStackFrame::Resolve { iface: _, spec } => {
                    writeln!(f, "  {line}: Resolve: {}", spec.name)?;
                }
                InjectionStackFrame::Build { instance, scope } => {
                    writeln!(f, "  {line}: Build:   {} <{}>", instance.name, scope.name)?;
                }
            }
        }
        Ok(())
    }
}