1use std::error::Error;
2use std::fmt;
3
4pub type BoxError = Box<dyn Error + Send + Sync>;
6
7#[derive(Debug)]
12#[non_exhaustive]
13pub enum ResolveError {
14 NotRegistered {
16 path: Vec<&'static str>,
18 },
19 ScopedFromRoot {
22 path: Vec<&'static str>,
24 },
25 Cycle {
28 path: Vec<&'static str>,
30 },
31 Construction {
33 path: Vec<&'static str>,
35 source: BoxError,
37 },
38}
39
40impl ResolveError {
41 pub fn path(&self) -> &[&'static str] {
43 match self {
44 Self::NotRegistered { path }
45 | Self::ScopedFromRoot { path }
46 | Self::Cycle { path }
47 | Self::Construction { path, .. } => path,
48 }
49 }
50}
51
52impl fmt::Display for ResolveError {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 let message = match self {
55 Self::NotRegistered { .. } => "service not registered",
56 Self::ScopedFromRoot { .. } => "scoped service resolved outside a scope",
57 Self::Cycle { .. } => "dependency cycle",
58 Self::Construction { .. } => "failed to construct service",
59 };
60 write!(f, "{message}: ")?;
61 write_path(f, self.path())
62 }
63}
64
65impl Error for ResolveError {
66 fn source(&self) -> Option<&(dyn Error + 'static)> {
67 match self {
68 Self::Construction { source, .. } => Some(source.as_ref()),
69 _ => None,
70 }
71 }
72}
73
74#[derive(Debug)]
76pub struct BuildError {
77 issues: Vec<BuildIssue>,
78}
79
80impl BuildError {
81 pub(crate) fn new(issues: Vec<BuildIssue>) -> Self {
82 Self { issues }
83 }
84
85 pub fn issues(&self) -> &[BuildIssue] {
88 &self.issues
89 }
90}
91
92impl fmt::Display for BuildError {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 for (i, issue) in self.issues.iter().enumerate() {
95 if i > 0 {
96 f.write_str("; ")?;
97 }
98 write!(f, "{issue}")?;
99 }
100 Ok(())
101 }
102}
103
104impl Error for BuildError {}
105
106#[derive(Debug, Clone, PartialEq, Eq)]
108#[non_exhaustive]
109pub enum BuildIssue {
110 Cycle {
113 path: Vec<&'static str>,
115 },
116 MissingDependency {
120 path: Vec<&'static str>,
122 },
123 CaptiveDependency {
128 path: Vec<&'static str>,
130 },
131}
132
133impl fmt::Display for BuildIssue {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 match self {
136 Self::Cycle { path } => {
137 f.write_str("dependency cycle: ")?;
138 write_path(f, path)
139 }
140 Self::MissingDependency { path } => {
141 f.write_str("dependency not registered: ")?;
142 write_path(f, path)
143 }
144 Self::CaptiveDependency { path } => {
145 f.write_str("singleton depends on scoped service: ")?;
146 write_path(f, path)
147 }
148 }
149 }
150}
151
152fn write_path(f: &mut fmt::Formatter<'_>, path: &[&'static str]) -> fmt::Result {
153 for (i, name) in path.iter().enumerate() {
154 if i > 0 {
155 f.write_str(" -> ")?;
156 }
157 f.write_str(name)?;
158 }
159 Ok(())
160}