use std::fmt::{self, Display, Formatter};
#[derive(Debug)]
pub enum DependencyInjectionError {
BuildFailed {
type_name: String,
source: Box<DependencyInjectionError>,
},
DependencyNotFound {
type_name: String,
},
CircularDependency,
}
impl DependencyInjectionError {
pub fn build_failed(type_name: impl Into<String>, source: DependencyInjectionError) -> Self {
Self::BuildFailed {
type_name: type_name.into(),
source: Box::new(source),
}
}
pub fn dependency_not_found(type_name: impl Into<String>) -> Self {
Self::DependencyNotFound {
type_name: type_name.into(),
}
}
pub fn diagnostic_context(&self) -> Vec<(String, String)> {
let mut context = Vec::new();
self.collect_diagnostic_context(&mut context);
context
}
pub fn dependency_path(&self) -> Option<&str> {
match self {
Self::BuildFailed { type_name, .. } => Some(type_name.as_str()),
Self::DependencyNotFound { .. } | Self::CircularDependency => None,
}
}
pub fn missing_dependency_path(&self) -> Option<&str> {
match self {
Self::BuildFailed { source, .. } => source.missing_dependency_path(),
Self::DependencyNotFound { type_name } => Some(type_name.as_str()),
Self::CircularDependency => None,
}
}
fn collect_diagnostic_context(&self, context: &mut Vec<(String, String)>) {
match self {
Self::BuildFailed { type_name, source } => {
context.push(("dependency_path".to_string(), type_name.clone()));
source.collect_diagnostic_context(context);
}
Self::DependencyNotFound { type_name } => {
context.push(("missing_dependency_path".to_string(), type_name.clone()));
}
Self::CircularDependency => {}
}
}
}
impl Display for DependencyInjectionError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::BuildFailed { type_name, source } => write!(
f,
"Failed to build dependency '{}': {}",
short_type_name(type_name),
source
),
Self::DependencyNotFound { type_name } => write!(
f,
"Dependency '{}' not found in dependency container",
short_type_name(type_name)
),
Self::CircularDependency => {
write!(f, "Circular dependency detected in dependency container")
}
}
}
}
impl std::error::Error for DependencyInjectionError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::BuildFailed { source, .. } => Some(source.as_ref()),
Self::DependencyNotFound { .. } | Self::CircularDependency => None,
}
}
}
fn short_type_name(type_name: &str) -> &str {
type_name.rsplit("::").next().unwrap_or(type_name)
}