use std::error::Error;
use std::fmt;
pub type BoxError = Box<dyn Error + Send + Sync>;
#[derive(Debug)]
#[non_exhaustive]
pub enum ResolveError {
NotRegistered {
path: Vec<&'static str>,
},
ScopedFromRoot {
path: Vec<&'static str>,
},
Cycle {
path: Vec<&'static str>,
},
Construction {
path: Vec<&'static str>,
source: BoxError,
},
}
impl ResolveError {
pub fn path(&self) -> &[&'static str] {
match self {
Self::NotRegistered { path }
| Self::ScopedFromRoot { path }
| Self::Cycle { path }
| Self::Construction { path, .. } => path,
}
}
}
impl fmt::Display for ResolveError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let message = match self {
Self::NotRegistered { .. } => "service not registered",
Self::ScopedFromRoot { .. } => "scoped service resolved outside a scope",
Self::Cycle { .. } => "dependency cycle",
Self::Construction { .. } => "failed to construct service",
};
write!(f, "{message}: ")?;
write_path(f, self.path())
}
}
impl Error for ResolveError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Construction { source, .. } => Some(source.as_ref()),
_ => None,
}
}
}
#[derive(Debug)]
pub struct BuildError {
issues: Vec<BuildIssue>,
}
impl BuildError {
pub(crate) fn new(issues: Vec<BuildIssue>) -> Self {
Self { issues }
}
pub fn issues(&self) -> &[BuildIssue] {
&self.issues
}
}
impl fmt::Display for BuildError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, issue) in self.issues.iter().enumerate() {
if i > 0 {
f.write_str("; ")?;
}
write!(f, "{issue}")?;
}
Ok(())
}
}
impl Error for BuildError {}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum BuildIssue {
Cycle {
path: Vec<&'static str>,
},
MissingDependency {
path: Vec<&'static str>,
},
CaptiveDependency {
path: Vec<&'static str>,
},
}
impl fmt::Display for BuildIssue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Cycle { path } => {
f.write_str("dependency cycle: ")?;
write_path(f, path)
}
Self::MissingDependency { path } => {
f.write_str("dependency not registered: ")?;
write_path(f, path)
}
Self::CaptiveDependency { path } => {
f.write_str("singleton depends on scoped service: ")?;
write_path(f, path)
}
}
}
}
fn write_path(f: &mut fmt::Formatter<'_>, path: &[&'static str]) -> fmt::Result {
for (i, name) in path.iter().enumerate() {
if i > 0 {
f.write_str(" -> ")?;
}
f.write_str(name)?;
}
Ok(())
}