liquid_core/error/result_ext.rs
1use std::error;
2use std::result;
3
4use super::CloneableError;
5use super::Error;
6use super::ErrorClone;
7use super::Result;
8
9/// `Result` extension methods for adapting third party errors to `Error`.
10pub trait ResultLiquidChainExt<T> {
11 /// Create an `Error` with `E` as the cause.
12 fn chain<S: Into<crate::model::KString>>(self, msg: S) -> Result<T>;
13
14 /// Create an `Error` with `E` as the cause.
15 fn chain_with<F>(self, msg: F) -> Result<T>
16 where
17 F: FnOnce() -> crate::model::KString;
18}
19
20/// `Result` extension methods for adapting third party errors to `Error`.
21pub trait ResultLiquidReplaceExt<T> {
22 /// Create an `Error` ignoring `E` as the cause.
23 ///
24 /// # Example
25 ///
26 /// ```rust
27 /// use std::io;
28 /// use liquid_core::error::Result;
29 /// use liquid_core::error::ResultLiquidReplaceExt;
30 ///
31 /// let error = Err(io::Error::new(io::ErrorKind::NotFound, "Oops"));
32 /// let error: Result<i32> = error.lossy_chain("Missing liquid partial");
33 /// ```
34 fn lossy_chain<S: Into<crate::model::KString>>(self, msg: S) -> Result<T>;
35
36 /// Create an `Error` ignoring `E` as the cause.
37 ///
38 /// # Example
39 ///
40 /// ```rust
41 /// use std::io;
42 /// use liquid_core::error::Result;
43 /// use liquid_core::error::ResultLiquidReplaceExt;
44 ///
45 /// let filename = "foo";
46 /// let error = Err(io::Error::new(io::ErrorKind::NotFound, "Oops"));
47 /// let error: Result<i32> = error
48 /// .lossy_chain_with(|| format!("Missing liquid partial: {}", filename).into());
49 /// ```
50 fn lossy_chain_with<F>(self, msg: F) -> Result<T>
51 where
52 F: FnOnce() -> crate::model::KString;
53
54 /// Create an `Error` ignoring `E` as the cause.
55 ///
56 /// # Example
57 ///
58 /// ```rust
59 /// use std::io;
60 /// use liquid_core::error::Result;
61 /// use liquid_core::error::ResultLiquidReplaceExt;
62 ///
63 /// let error = Err(io::Error::new(io::ErrorKind::NotFound, "Oops"));
64 /// let error: Result<i32> = error.replace("Missing liquid partial");
65 /// ```
66 fn replace<S: Into<crate::model::KString>>(self, msg: S) -> Result<T>;
67
68 /// Create an `Error` ignoring `E` as the cause.
69 ///
70 /// # Example
71 ///
72 /// ```rust
73 /// use std::io;
74 /// use liquid_core::error::Result;
75 /// use liquid_core::error::ResultLiquidReplaceExt;
76 ///
77 /// let filename = "foo";
78 /// let error = Err(io::Error::new(io::ErrorKind::NotFound, "Oops"));
79 /// let error: Result<i32> = error
80 /// .replace_with(|| format!("Missing liquid partial: {}", filename).into());
81 /// ```
82 fn replace_with<F>(self, msg: F) -> Result<T>
83 where
84 F: FnOnce() -> crate::model::KString;
85}
86
87impl<T, E> ResultLiquidChainExt<T> for result::Result<T, E>
88where
89 E: ErrorClone,
90{
91 fn chain<S: Into<crate::model::KString>>(self, msg: S) -> Result<T> {
92 self.map_err(|err| Error::with_msg(msg).cause(err))
93 }
94
95 fn chain_with<F>(self, msg: F) -> Result<T>
96 where
97 F: FnOnce() -> crate::model::KString,
98 {
99 self.map_err(|err| Error::with_msg(msg()).cause(err))
100 }
101}
102
103impl<T, E> ResultLiquidReplaceExt<T> for result::Result<T, E>
104where
105 E: error::Error + Send + Sync + 'static,
106{
107 fn lossy_chain<S: Into<crate::model::KString>>(self, msg: S) -> Result<T> {
108 self.map_err(|err| Error::with_msg(msg).cause(CloneableError::new(err)))
109 }
110
111 fn lossy_chain_with<F>(self, msg: F) -> Result<T>
112 where
113 F: FnOnce() -> crate::model::KString,
114 {
115 self.map_err(|err| Error::with_msg(msg()).cause(CloneableError::new(err)))
116 }
117
118 fn replace<S: Into<crate::model::KString>>(self, msg: S) -> Result<T> {
119 self.map_err(|_| Error::with_msg(msg))
120 }
121
122 fn replace_with<F>(self, msg: F) -> Result<T>
123 where
124 F: FnOnce() -> crate::model::KString,
125 {
126 self.map_err(|_| Error::with_msg(msg()))
127 }
128}
129
130/// Add context to a `crate::error::Error`.
131pub trait ResultLiquidExt<T>
132where
133 Self: ::std::marker::Sized,
134{
135 /// Add a new stack frame to the `crate::error::Error`.
136 ///
137 /// # Example
138 ///
139 /// ```rust
140 /// use liquid_core::error::Error;
141 /// use liquid_core::error::Result;
142 /// use liquid_core::error::ResultLiquidExt;
143 ///
144 /// let error: Result<i32> = Err(Error::with_msg("Oops"));
145 /// let error = error.trace("Within forloop");
146 /// ```
147 fn trace<S>(self, trace: S) -> Result<T>
148 where
149 S: Into<crate::model::KString>;
150
151 /// Add a new stack frame to the `crate::error::Error`.
152 ///
153 /// # Example
154 ///
155 /// ```rust
156 /// use liquid_core::error::Error;
157 /// use liquid_core::error::Result;
158 /// use liquid_core::error::ResultLiquidExt;
159 ///
160 /// let for_var = "foo";
161 /// let error: Result<i32> = Err(Error::with_msg("Oops"));
162 /// let error = error.trace_with(|| format!("Within forloop with {}", for_var).into());
163 /// ```
164 fn trace_with<F>(self, trace: F) -> Result<T>
165 where
166 F: FnOnce() -> crate::model::KString;
167
168 /// Add state the current stack frame.
169 ///
170 /// # Example
171 ///
172 /// ```rust
173 /// use liquid_core::error::Error;
174 /// use liquid_core::error::Result;
175 /// use liquid_core::error::ResultLiquidExt;
176 ///
177 /// let for_var = "foo";
178 /// let error: Result<i32> = Err(Error::with_msg("Oops"));
179 /// let error = error
180 /// .context_key("foo")
181 /// .value("10");
182 /// let error = error
183 /// .context_key("foo")
184 /// .value_with(|| format!("{}", for_var).into());
185 /// ```
186 #[must_use]
187 fn context_key<S>(self, key: S) -> Key<T>
188 where
189 S: Into<crate::model::KString>;
190
191 /// Add state the current stack frame.
192 ///
193 /// # Example
194 ///
195 /// ```rust
196 /// use liquid_core::error::Error;
197 /// use liquid_core::error::Result;
198 /// use liquid_core::error::ResultLiquidExt;
199 ///
200 /// let for_var = "foo";
201 /// let error: Result<i32> = Err(Error::with_msg("Oops"));
202 /// let error = error
203 /// .context_key_with(|| format!("{}", 10).into())
204 /// .value("10");
205 /// let error = error
206 /// .context_key_with(|| format!("{}", 10).into())
207 /// .value_with(|| format!("{}", for_var).into());
208 /// ```
209 #[must_use]
210 fn context_key_with<F>(self, key: F) -> FnKey<T, F>
211 where
212 F: FnOnce() -> crate::model::KString;
213}
214
215impl<T> ResultLiquidExt<T> for Result<T> {
216 fn trace<S>(self, trace: S) -> Result<T>
217 where
218 S: Into<crate::model::KString>,
219 {
220 self.map_err(|err| err.trace(trace))
221 }
222
223 fn trace_with<F>(self, trace: F) -> Result<T>
224 where
225 F: FnOnce() -> crate::model::KString,
226 {
227 self.map_err(|err| err.trace(trace()))
228 }
229
230 fn context_key<S>(self, key: S) -> Key<T>
231 where
232 S: Into<crate::model::KString>,
233 {
234 Key::new(self, key)
235 }
236
237 fn context_key_with<F>(self, key: F) -> FnKey<T, F>
238 where
239 F: FnOnce() -> crate::model::KString,
240 {
241 FnKey::new(self, key)
242 }
243}
244
245/// Partially constructed context (missing value) for `Result<T>`.
246#[allow(missing_debug_implementations)]
247pub struct Key<T> {
248 builder: Result<T>,
249 key: crate::model::KString,
250}
251
252impl<T> Key<T> {
253 /// Save off a key for a context that will be added to `builder`.
254 #[must_use]
255 pub fn new<S>(builder: Result<T>, key: S) -> Self
256 where
257 S: Into<crate::model::KString>,
258 {
259 Self {
260 builder,
261 key: key.into(),
262 }
263 }
264
265 /// Finish creating context and add it to `Result<T>`.
266 pub fn value<S>(self, value: S) -> Result<T>
267 where
268 S: Into<crate::model::KString>,
269 {
270 let builder = self.builder;
271 let key = self.key;
272 builder.map_err(|err| err.context(key, value.into()))
273 }
274
275 /// Finish creating context and add it to `Result<T>`.
276 pub fn value_with<F>(self, value: F) -> Result<T>
277 where
278 F: FnOnce() -> crate::model::KString,
279 {
280 let builder = self.builder;
281 let key = self.key;
282 builder.map_err(|err| err.context(key, value()))
283 }
284}
285
286/// Partially constructed context (missing value) for `Result<T>`.
287#[allow(missing_debug_implementations)]
288pub struct FnKey<T, F>
289where
290 F: FnOnce() -> crate::model::KString,
291{
292 builder: Result<T>,
293 key: F,
294}
295
296impl<T, F> FnKey<T, F>
297where
298 F: FnOnce() -> crate::model::KString,
299{
300 /// Save off a key for a context that will be added to `builder`.
301 #[must_use]
302 pub fn new(builder: Result<T>, key: F) -> Self {
303 Self { builder, key }
304 }
305
306 /// Finish creating context and add it to `Result<T>`.
307 pub fn value<S>(self, value: S) -> Result<T>
308 where
309 S: Into<crate::model::KString>,
310 {
311 let builder = self.builder;
312 let key = self.key;
313 builder.map_err(|err| err.context((key)(), value.into()))
314 }
315
316 /// Finish creating context and add it to `Result<T>`.
317 pub fn value_with<V>(self, value: V) -> Result<T>
318 where
319 V: FnOnce() -> crate::model::KString,
320 {
321 let builder = self.builder;
322 let key = self.key;
323 builder.map_err(|err| err.context((key)(), value()))
324 }
325}