neuer_error/
results.rs

1//! Helpers on `Result` types for conversion and context addition.
2
3use ::alloc::borrow::Cow;
4
5use crate::{
6	NeuErr,
7	features::{AnyDebugSendSync, ErrorSendSync},
8};
9
10/// Helper on our [`Result`](crate::Result)s for context addition and modification.
11pub trait CtxResultExt: Sized {
12	/// Add human context to the error.
13	#[track_caller]
14	#[must_use]
15	fn context<C>(self, context: C) -> Self
16	where
17		C: Into<Cow<'static, str>>;
18
19	/// Add human context to the error via a closure.
20	#[track_caller]
21	#[must_use]
22	fn context_with<F, C>(self, context_fn: F) -> Self
23	where
24		F: FnOnce() -> C,
25		C: Into<Cow<'static, str>>;
26
27	/// Add machine context to the error.
28	///
29	/// This will not override existing attachments. If you want to replace and override any
30	/// existing attachments of the same type, use `attach_override` instead.
31	#[must_use]
32	fn attach<C>(self, context: C) -> Self
33	where
34		C: AnyDebugSendSync + 'static;
35
36	/// Add machine context to the error via a closure.
37	///
38	/// This will not override existing attachments. If you want to replace and override any
39	/// existing attachments of the same type, use `attach_override` instead.
40	#[must_use]
41	fn attach_with<F, C>(self, context_fn: F) -> Self
42	where
43		F: FnOnce() -> C,
44		C: AnyDebugSendSync + 'static;
45
46	/// Set machine context in the error.
47	///
48	/// This will override existing attachments of the same type. If you want to add attachments of
49	/// the same type, use `attach` instead.
50	#[must_use]
51	fn attach_override<C>(self, context: C) -> Self
52	where
53		C: AnyDebugSendSync + 'static;
54
55	/// Set machine context in the error via a closure.
56	///
57	/// This will override existing attachments of the same type. If you want to add attachments of
58	/// the same type, use `attach` instead.
59	#[must_use]
60	fn attach_override_with<F, C>(self, context_fn: F) -> Self
61	where
62		F: FnOnce() -> C,
63		C: AnyDebugSendSync + 'static;
64}
65
66impl<T> CtxResultExt for Result<T, NeuErr> {
67	#[track_caller]
68	#[inline]
69	fn context<C>(self, context: C) -> Self
70	where
71		C: Into<Cow<'static, str>>,
72	{
73		// Cannot use `map_err` because closures cannot have `#[track_caller]` yet.
74		match self {
75			Ok(value) => Ok(value),
76			Err(err) => Err(err.context(context)),
77		}
78	}
79
80	#[track_caller]
81	#[inline]
82	fn context_with<F, C>(self, context_fn: F) -> Self
83	where
84		F: FnOnce() -> C,
85		C: Into<Cow<'static, str>>,
86	{
87		// Cannot use `map_err` because closures cannot have `#[track_caller]` yet.
88		match self {
89			Ok(value) => Ok(value),
90			Err(err) => Err(err.context(context_fn())),
91		}
92	}
93
94	#[inline]
95	fn attach<C>(self, context: C) -> Self
96	where
97		C: AnyDebugSendSync + 'static,
98	{
99		self.map_err(|err| err.attach(context))
100	}
101
102	#[inline]
103	fn attach_with<F, C>(self, context_fn: F) -> Self
104	where
105		F: FnOnce() -> C,
106		C: AnyDebugSendSync + 'static,
107	{
108		self.map_err(|err| err.attach(context_fn()))
109	}
110
111	#[inline]
112	fn attach_override<C>(self, context: C) -> Self
113	where
114		C: AnyDebugSendSync + 'static,
115	{
116		self.map_err(|err| err.attach_override(context))
117	}
118
119	#[inline]
120	fn attach_override_with<F, C>(self, context_fn: F) -> Self
121	where
122		F: FnOnce() -> C,
123		C: AnyDebugSendSync + 'static,
124	{
125		self.map_err(|err| err.attach_override(context_fn()))
126	}
127}
128
129
130/// Helper on `Result`s with external `Error`s for conversion to our `NeuErr`.
131pub trait ConvertResult<T, E>: Sized {
132	/// Add human context to the error.
133	#[track_caller]
134	fn context<C>(self, context: C) -> Result<T, NeuErr>
135	where
136		C: Into<Cow<'static, str>>;
137
138	/// Add human context to the error via a closure.
139	#[track_caller]
140	fn context_with<F, C>(self, context_fn: F) -> Result<T, NeuErr>
141	where
142		F: FnOnce(&E) -> C,
143		C: Into<Cow<'static, str>>;
144
145	/// Add machine context to the error.
146	///
147	/// This will not override existing attachments. If you want to replace and override any
148	/// existing attachments of the same type, use `attach_override` instead.
149	fn attach<C>(self, context: C) -> Result<T, NeuErr>
150	where
151		C: AnyDebugSendSync + 'static;
152
153	/// Add machine context to the error via a closure.
154	///
155	/// This will not override existing attachments. If you want to replace and override any
156	/// existing attachments of the same type, use `attach_override` instead.
157	fn attach_with<F, C>(self, context_fn: F) -> Result<T, NeuErr>
158	where
159		F: FnOnce(&E) -> C,
160		C: AnyDebugSendSync + 'static;
161
162	/// Set machine context in the error.
163	///
164	/// This will override existing attachments of the same type. If you want to add attachments of
165	/// the same type, use `attach` instead.
166	fn attach_override<C>(self, context: C) -> Result<T, NeuErr>
167	where
168		C: AnyDebugSendSync + 'static;
169
170	/// Set machine context in the error via a closure.
171	///
172	/// This will override existing attachments of the same type. If you want to add attachments of
173	/// the same type, use `attach` instead.
174	fn attach_override_with<F, C>(self, context_fn: F) -> Result<T, NeuErr>
175	where
176		F: FnOnce(&E) -> C,
177		C: AnyDebugSendSync + 'static;
178}
179
180impl<T, E> ConvertResult<T, E> for Result<T, E>
181where
182	E: ErrorSendSync + 'static,
183{
184	#[track_caller]
185	#[inline]
186	fn context<C>(self, context: C) -> Result<T, NeuErr>
187	where
188		C: Into<Cow<'static, str>>,
189	{
190		// Cannot use `map_err` because closures cannot have `#[track_caller]` yet.
191		match self {
192			Ok(value) => Ok(value),
193			Err(err) => Err(NeuErr::from_source(err).context(context)),
194		}
195	}
196
197	#[track_caller]
198	#[inline]
199	fn context_with<F, C>(self, context_fn: F) -> Result<T, NeuErr>
200	where
201		F: FnOnce(&E) -> C,
202		C: Into<Cow<'static, str>>,
203	{
204		// Cannot use `map_err` because closures cannot have `#[track_caller]` yet.
205		match self {
206			Ok(value) => Ok(value),
207			Err(err) => {
208				let context = context_fn(&err);
209				Err(NeuErr::from_source(err).context(context))
210			}
211		}
212	}
213
214	#[inline]
215	fn attach<C>(self, context: C) -> Result<T, NeuErr>
216	where
217		C: AnyDebugSendSync + 'static,
218	{
219		self.map_err(|err| NeuErr::from_source(err).attach(context))
220	}
221
222	#[inline]
223	fn attach_with<F, C>(self, context_fn: F) -> Result<T, NeuErr>
224	where
225		F: FnOnce(&E) -> C,
226		C: AnyDebugSendSync + 'static,
227	{
228		self.map_err(|err| {
229			let attach = context_fn(&err);
230			NeuErr::from_source(err).attach(attach)
231		})
232	}
233
234	#[inline]
235	fn attach_override<C>(self, context: C) -> Result<T, NeuErr>
236	where
237		C: AnyDebugSendSync + 'static,
238	{
239		self.map_err(|err| NeuErr::from_source(err).attach_override(context))
240	}
241
242	#[inline]
243	fn attach_override_with<F, C>(self, context_fn: F) -> Result<T, NeuErr>
244	where
245		F: FnOnce(&E) -> C,
246		C: AnyDebugSendSync + 'static,
247	{
248		self.map_err(|err| {
249			let attach = context_fn(&err);
250			NeuErr::from_source(err).attach_override(attach)
251		})
252	}
253}
254
255
256/// Helper on `Option`s for conversion to our `Result`s.
257pub trait ConvertOption<T>: Sized {
258	/// Convert `None` to an error and add human context to the error.
259	#[track_caller]
260	fn context<C>(self, context: C) -> Result<T, NeuErr>
261	where
262		C: Into<Cow<'static, str>>;
263
264	/// Convert `None` to an error and add human context to the error via a closure.
265	#[track_caller]
266	fn context_with<F, C>(self, context_fn: F) -> Result<T, NeuErr>
267	where
268		F: FnOnce() -> C,
269		C: Into<Cow<'static, str>>;
270
271	/// Convert `None` to an error and add machine context to the error.
272	///
273	/// This will not override existing attachments. If you want to replace and override any
274	/// existing attachments of the same type, use `attach_override` instead.
275	fn attach<C>(self, context: C) -> Result<T, NeuErr>
276	where
277		C: AnyDebugSendSync + 'static;
278
279	/// Convert `None` to an error and add machine context to the error via a closure.
280	///
281	/// This will not override existing attachments. If you want to replace and override any
282	/// existing attachments of the same type, use `attach_override` instead.
283	fn attach_with<F, C>(self, context_fn: F) -> Result<T, NeuErr>
284	where
285		F: FnOnce() -> C,
286		C: AnyDebugSendSync + 'static;
287
288	/// Convert `None` to an error and set machine context in the error.
289	///
290	/// This will override existing attachments of the same type. If you want to add attachments of
291	/// the same type, use `attach` instead.
292	fn attach_override<C>(self, context: C) -> Result<T, NeuErr>
293	where
294		C: AnyDebugSendSync + 'static;
295
296	/// Convert `None` to an error and set machine context in the error via a closure.
297	///
298	/// This will override existing attachments of the same type. If you want to add attachments of
299	/// the same type, use `attach` instead.
300	fn attach_override_with<F, C>(self, context_fn: F) -> Result<T, NeuErr>
301	where
302		F: FnOnce() -> C,
303		C: AnyDebugSendSync + 'static;
304}
305
306impl<T> ConvertOption<T> for Option<T> {
307	#[track_caller]
308	#[inline]
309	fn context<C>(self, context: C) -> Result<T, NeuErr>
310	where
311		C: Into<Cow<'static, str>>,
312	{
313		// Cannot use `ok_or_else` because closures cannot have `#[track_caller]` yet.
314		match self {
315			Some(value) => Ok(value),
316			None => Err(NeuErr::new(context)),
317		}
318	}
319
320	#[track_caller]
321	#[inline]
322	fn context_with<F, C>(self, context_fn: F) -> Result<T, NeuErr>
323	where
324		F: FnOnce() -> C,
325		C: Into<Cow<'static, str>>,
326	{
327		// Cannot use `ok_or_else` because closures cannot have `#[track_caller]` yet.
328		match self {
329			Some(value) => Ok(value),
330			None => {
331				let context = context_fn();
332				Err(NeuErr::new(context))
333			}
334		}
335	}
336
337	#[inline]
338	fn attach<C>(self, context: C) -> Result<T, NeuErr>
339	where
340		C: AnyDebugSendSync + 'static,
341	{
342		self.ok_or_else(|| NeuErr::default().attach(context))
343	}
344
345	#[inline]
346	fn attach_with<F, C>(self, context_fn: F) -> Result<T, NeuErr>
347	where
348		F: FnOnce() -> C,
349		C: AnyDebugSendSync + 'static,
350	{
351		self.ok_or_else(|| {
352			let attach = context_fn();
353			NeuErr::default().attach(attach)
354		})
355	}
356
357	#[inline]
358	fn attach_override<C>(self, context: C) -> Result<T, NeuErr>
359	where
360		C: AnyDebugSendSync + 'static,
361	{
362		self.ok_or_else(|| NeuErr::default().attach_override(context))
363	}
364
365	#[inline]
366	fn attach_override_with<F, C>(self, context_fn: F) -> Result<T, NeuErr>
367	where
368		F: FnOnce() -> C,
369		C: AnyDebugSendSync + 'static,
370	{
371		self.ok_or_else(|| {
372			let attach = context_fn();
373			NeuErr::default().attach_override(attach)
374		})
375	}
376}
377
378
379/// Helpers on `Result`s.
380pub trait ResultExt<T, E> {
381	/// Consumes the error from the `Result` and pushes it into the provided collection.
382	fn or_collect<C>(self, collection: &mut C) -> Option<T>
383	where
384		C: Extend<E>;
385}
386
387impl<T, E> ResultExt<T, E> for Result<T, E> {
388	#[inline]
389	fn or_collect<C>(self, collection: &mut C) -> Option<T>
390	where
391		C: Extend<E>,
392	{
393		match self {
394			Ok(value) => Some(value),
395			Err(err) => {
396				collection.extend(core::iter::once(err));
397				None
398			}
399		}
400	}
401}