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}