Skip to main content

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