module_util/file/error.rs
1//! [`File`] error.
2//!
3//! [`File`]: super::File
4
5use std::fmt;
6use std::path::PathBuf;
7use std::string::ToString;
8
9use crate::evaluator::Trace;
10use crate::evaluator::dfs;
11
12///////////////////////////////////////////////////////////////////////////////
13
14/// Error for the [`File`] evaluator.
15///
16/// # Example
17///
18/// ```rust
19/// # use module_util::file::error::Error;
20/// use module_util::evaluator::dfs;
21///
22/// let mut err = Error::new(dfs::Error::Merge({
23/// let mut e = module::merge::Error::collision();
24/// e.field.push_back("my");
25/// e.field.push_back("super");
26/// e.field.push_back("awesome");
27/// e.field.push_back("field");
28/// e
29/// }));
30///
31/// err.trace.push("module 1".into());
32/// err.trace.push("module 2".into());
33/// err.trace.push("module 3".into());
34///
35/// assert_eq!(format!("{err}"),
36/// r#"value collision while evaluating "my.super.awesome.field"
37///
38/// in module 3
39/// from module 2
40/// from module 1
41/// "#);
42///
43/// assert_eq!(format!("{err}"), format!("{err:#}"));
44/// ```
45///
46/// ```rust
47/// # use module_util::file::error::Error;
48/// use module_util::evaluator::dfs;
49///
50/// let mut err = Error::new(dfs::Error::Merge(module::merge::Error::collision()));
51///
52/// err.trace.push("module 1".into());
53///
54/// assert_eq!(format!("{err}"),
55/// r#"value collision
56///
57/// in module 1
58/// "#);
59///
60/// assert_eq!(format!("{err}"), format!("{err:#}"));
61/// ```
62///
63/// ```rust
64/// # use module_util::file::error::Error;
65/// use module_util::evaluator::dfs;
66/// use std::io;
67///
68/// let mut err = Error::new({
69/// let mut e = module::merge::Error::other(io::Error::other("invalid data"));
70/// e.field.push_back("user");
71/// e.field.push_back("email");
72/// dfs::Error::Merge(e)
73/// });
74///
75/// err.trace.push("module 1".into());
76/// err.trace.push("module 2".into());
77///
78/// assert_eq!(format!("{err}"),
79/// r#"invalid data while evaluating "user.email"
80///
81/// in module 2
82/// from module 1
83/// "#);
84///
85/// assert_eq!(format!("{err}"), format!("{err:#}"));
86/// ```
87///
88/// ```rust
89/// # use module_util::file::error::Error;
90/// use module_util::evaluator::{dfs, Trace};
91/// use std::io;
92///
93/// let err = Error::new(dfs::Error::other(io::Error::other("some other error")))
94/// .with_trace({
95/// let mut t = Trace::empty();
96/// t.push("module 1".into());
97/// t.push("module 2".into());
98/// t.push("module 3".into());
99/// t
100/// });
101///
102/// assert_eq!(format!("{err}"),
103/// r#"some other error
104///
105/// in module 3
106/// from module 2
107/// from module 1
108/// "#);
109///
110/// assert_eq!(format!("{err}"), format!("{err:#}"));
111/// ```
112///
113/// [`File`]: super::File
114#[expect(clippy::manual_non_exhaustive)]
115pub struct Error {
116 _priv: (),
117
118 /// Evaluation error.
119 pub error: dfs::Error,
120
121 /// Module trace.
122 pub trace: Trace<PathBuf>,
123}
124
125impl fmt::Debug for Error {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 f.debug_struct("Error")
128 .field("error", &self.error)
129 .field("trace", &self.trace)
130 .finish()
131 }
132}
133
134impl fmt::Display for Error {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 match self.error {
137 dfs::Error::Merge(ref e) => {
138 e.message(f)?;
139
140 if !e.field.is_empty() {
141 write!(f, " while evaluating {:?}", e.field)?;
142 }
143
144 writeln!(f)?;
145 }
146
147 dfs::Error::Other(ref e) => {
148 writeln!(f, "{}", e.to_string().trim_end())?;
149 }
150 }
151
152 let mut trace = self.trace.iter().rev();
153 if let Some(first) = trace.next() {
154 writeln!(f)?;
155 writeln!(f, " in {}", first.display())?;
156 for path in trace {
157 writeln!(f, " from {}", path.display())?;
158 }
159 }
160
161 Ok(())
162 }
163}
164
165impl std::error::Error for Error {}
166
167impl Error {
168 /// Create a new [`Error`].
169 #[must_use]
170 pub const fn new(error: dfs::Error) -> Self {
171 Self {
172 _priv: (),
173 error,
174 trace: Trace::empty(),
175 }
176 }
177
178 /// Set the `trace` of the error.
179 #[must_use]
180 pub fn with_trace(mut self, trace: Trace<PathBuf>) -> Self {
181 self.trace = trace;
182 self
183 }
184}