Skip to main content

wiwi_err/
lib.rs

1pub use core::error::Error as ErrorTrait;
2use core::panic::Location;
3use core::fmt::{ self, Debug, Display };
4
5pub mod prelude;
6#[cfg(feature = "axum-0-8")]
7mod axum_0_8;
8
9pub struct Err<E> {
10	// use box to make stack size smaller
11	frame: Box<TypedFrame<E>>
12}
13
14impl<E> Err<E>
15where
16	E: ErrorTrait + Send + Sync + 'static
17{
18	#[inline]
19	#[track_caller]
20	pub fn from_err(err: E) -> Self {
21		let children = walk(&err);
22
23		Err {
24			frame: Box::new(TypedFrame {
25				err,
26				location: Location::caller(),
27				children
28			})
29		}
30	}
31
32	#[inline]
33	#[track_caller]
34	pub fn from_errs<C>(err: E, children: &mut dyn Iterator<Item = C>) -> Self
35	where
36		C: ErrorTrait + Send + Sync + 'static
37	{
38		let (len, _) = children.size_hint();
39		let mut processed_children = Vec::with_capacity(len);
40		for err in children {
41			let children = walk(&err);
42
43			processed_children.push(Frame {
44				err: Box::new(err),
45				location: Location::caller(),
46				children
47			});
48		}
49
50		Err {
51			frame: Box::new(TypedFrame {
52				err,
53				location: Location::caller(),
54				children: processed_children
55			})
56		}
57	}
58
59	#[inline]
60	#[track_caller]
61	pub fn raise<E2>(self, err: E2) -> Err<E2>
62	where
63		E2: ErrorTrait + Send + Sync + 'static
64	{
65		let mut new = Err::from_err(err);
66		new.frame.children.push((*self.frame).into());
67		new
68	}
69
70	#[inline]
71	pub fn as_inner(&self) -> &E {
72		&self.frame.err
73	}
74
75	#[inline]
76	pub fn simple_display(&self) -> SimpleDisplay<'_, E> {
77		SimpleDisplay { inner: self }
78	}
79
80	#[inline]
81	pub fn detailed_display(&self) -> DetailedDisplay<'_, E> {
82		DetailedDisplay { inner: self }
83	}
84
85	#[inline]
86	pub fn as_error(&self) -> ErrorImplementorBorrowed<'_, E> {
87		ErrorImplementorBorrowed { inner: self }
88	}
89
90	#[inline]
91	pub fn into_error(self) -> ErrorImplementorOwned<E> {
92		ErrorImplementorOwned { inner: self }
93	}
94}
95
96impl<E> Debug for Err<E>
97where
98	E: ErrorTrait + Send + Sync + 'static
99{
100	#[inline]
101	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102		self.detailed_display().fmt(f)
103	}
104}
105
106struct TypedFrame<E> {
107	err: E,
108	location: &'static Location<'static>,
109	children: Vec<Frame>
110}
111
112struct Frame {
113	err: Box<dyn ErrorTrait + Send + Sync + 'static>,
114	location: &'static Location<'static>,
115	children: Vec<Frame>
116}
117
118impl<E> From<TypedFrame<E>> for Frame
119where
120	E: ErrorTrait + Send + Sync + 'static
121{
122	#[inline]
123	fn from(frame: TypedFrame<E>) -> Self {
124		let TypedFrame { err, location, children } = frame;
125		let err = Box::new(err);
126		Frame { err, location, children }
127	}
128}
129
130struct BorrowedFrame<'h> {
131	err: &'h (dyn ErrorTrait + Send + Sync + 'static),
132	location: &'static Location<'static>,
133	children: &'h [Frame]
134}
135
136impl<'h, E> From<&'h TypedFrame<E>> for BorrowedFrame<'h>
137where
138	E: ErrorTrait + Send + Sync + 'static
139{
140	#[inline]
141	fn from(frame: &'h TypedFrame<E>) -> Self {
142		let TypedFrame { err, location, children } = frame;
143		Self { err, location, children }
144	}
145}
146
147impl<'h> From<&'h Frame> for BorrowedFrame<'h> {
148	#[inline]
149	fn from(frame: &'h Frame) -> Self {
150		let Frame { err, location, children } = frame;
151		Self { err: &**err, location, children }
152	}
153}
154
155pub struct SimpleDisplay<'h, E> {
156	inner: &'h Err<E>
157}
158
159impl<'h, E> Display for SimpleDisplay<'h, E>
160where
161	E: ErrorTrait + Send + Sync + 'static
162{
163	#[inline]
164	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165		Display::fmt(&self.inner.frame.err, f)
166	}
167}
168
169pub struct DetailedDisplay<'h, E> {
170	inner: &'h Err<E>
171}
172
173impl<'h, E> Display for DetailedDisplay<'h, E>
174where
175	E: ErrorTrait + Send + Sync + 'static
176{
177	#[inline]
178	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179		print_err_dbg(
180			f,
181			(&*self.inner.frame).into(),
182			0,
183			&mut String::new()
184		)
185	}
186}
187
188pub struct ErrorImplementorBorrowed<'h, E> {
189	inner: &'h Err<E>
190}
191
192impl<'h, E> ErrorImplementorBorrowed<'h, E> {
193	#[inline]
194	pub fn as_err(&self) -> &Err<E> {
195		self.inner
196	}
197}
198
199impl<'h, E> Debug for ErrorImplementorBorrowed<'h, E>
200where
201	E: ErrorTrait + Send + Sync + 'static
202{
203	#[inline]
204	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205		self.inner.detailed_display().fmt(f)
206	}
207}
208
209impl<'h, E> Display for ErrorImplementorBorrowed<'h, E>
210where
211	E: ErrorTrait + Send + Sync + 'static
212{
213	#[inline]
214	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215		self.inner.simple_display().fmt(f)
216	}
217}
218
219impl<'h, E> ErrorTrait for ErrorImplementorBorrowed<'h, E>
220where
221	E: ErrorTrait + Send + Sync + 'static
222{}
223
224pub struct ErrorImplementorOwned<E> {
225	inner: Err<E>
226}
227
228impl<E> ErrorImplementorOwned<E> {
229	#[inline]
230	pub fn as_err(&self) -> &Err<E> {
231		&self.inner
232	}
233
234	#[inline]
235	pub fn into_err(self) -> Err<E> {
236		self.inner
237	}
238}
239
240impl<E> Debug for ErrorImplementorOwned<E>
241where
242	E: ErrorTrait + Send + Sync + 'static
243{
244	#[inline]
245	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246		self.inner.detailed_display().fmt(f)
247	}
248}
249
250impl<E> Display for ErrorImplementorOwned<E>
251where
252	E: ErrorTrait + Send + Sync + 'static
253{
254	#[inline]
255	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256		self.inner.simple_display().fmt(f)
257	}
258}
259
260impl<E> ErrorTrait for ErrorImplementorOwned<E>
261where
262	E: ErrorTrait + Send + Sync + 'static
263{}
264
265struct StringError {
266	debug: Box<str>,
267	display: Box<str>
268}
269
270impl Debug for StringError {
271	#[inline]
272	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273		f.write_str(&self.debug)
274	}
275}
276
277impl Display for StringError {
278	#[inline]
279	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
280		f.write_str(&self.display)
281	}
282}
283
284impl ErrorTrait for StringError {}
285
286#[track_caller]
287fn walk(err: &dyn ErrorTrait) -> Vec<Frame> {
288	if let Some(err) = err.source() {
289		vec![Frame {
290			err: Box::new(StringError {
291				debug: format!("{err:?}").into_boxed_str(),
292				display: format!("{err}").into_boxed_str()
293			}),
294			location: Location::caller(),
295			children: walk(err)
296		}]
297	} else {
298		Vec::new()
299	}
300}
301
302fn print_err_dbg(
303	f: &mut fmt::Formatter<'_>,
304	frame: BorrowedFrame<'_>,
305	level: usize,
306	prefix_buf: &mut String
307) -> fmt::Result {
308	let prefix_buf_len = prefix_buf.len();
309	let level_in_spaces = level * 2;
310	if prefix_buf_len < level_in_spaces {
311		let additional = level_in_spaces - prefix_buf_len;
312
313		prefix_buf.reserve(additional);
314		(0..additional).for_each(|_| prefix_buf.push(' '));
315	}
316	let prefix = &prefix_buf[..level_in_spaces];
317
318	write!(
319		f,
320		"{prefix}- err in {file}, at {line}:{col}",
321		file = frame.location.file(),
322		line = frame.location.line(),
323		col = frame.location.column()
324	)?;
325
326	write!(f, "\n{prefix}  {}", frame.err)?;
327
328	if !frame.children.is_empty() {
329		write!(f, "\n{prefix}  caused by:")?;
330	}
331
332	for child in frame.children {
333		writeln!(f)?;
334		print_err_dbg(f, child.into(), level + 1, prefix_buf)?;
335	}
336
337	Ok(())
338}
339
340pub trait ErrorExt {
341	fn raise(self) -> Err<Self>
342	where
343		Self: Sized;
344}
345
346impl<E> ErrorExt for E
347where
348	E: ErrorTrait + Send + Sync + 'static
349{
350	#[inline]
351	#[track_caller]
352	fn raise(self) -> Err<Self> {
353		Err::from_err(self)
354	}
355}
356
357pub trait OptionExt {
358	type Ok;
359
360	fn or_raise<E>(self, err: impl FnOnce() -> E) -> Result<Self::Ok, Err<E>>
361	where
362		E: ErrorTrait + Send + Sync + 'static;
363}
364
365impl<T> OptionExt for Option<T> {
366	type Ok = T;
367
368	#[inline]
369	#[track_caller]
370	fn or_raise<E>(self, err: impl FnOnce() -> E) -> Result<T, Err<E>>
371	where
372		E: ErrorTrait + Send + Sync + 'static
373	{
374		match self {
375			Some(value) => { Ok(value) }
376			None => { Err(Err::from_err(err())) }
377		}
378	}
379}
380
381pub trait ResultExt {
382	type Ok;
383	type Err;
384
385	fn or_raise<E>(self, err: impl FnOnce() -> E) -> Result<Self::Ok, Err<E>>
386	where
387		E: ErrorTrait + Send + Sync + 'static;
388}
389
390impl<T, E> ResultExt for Result<T, E>
391where
392	E: ErrorTrait + Send + Sync + 'static
393{
394	type Ok = T;
395	type Err = E;
396
397	#[inline]
398	#[track_caller]
399	fn or_raise<E2>(self, err: impl FnOnce() -> E2) -> Result<T, Err<E2>>
400	where
401		E2: ErrorTrait + Send + Sync + 'static
402	{
403		match self {
404			Ok(value) => { Ok(value) }
405			Err(prev_err) => { Err(Err::from_err(prev_err).raise(err())) }
406		}
407	}
408}
409
410impl<T, E> ResultExt for Result<T, Err<E>>
411where
412	E: ErrorTrait + Send + Sync + 'static
413{
414	type Ok = T;
415	type Err = E;
416
417	#[inline]
418	#[track_caller]
419	fn or_raise<E2>(self, err: impl FnOnce() -> E2) -> Result<T, Err<E2>>
420	where
421		E2: ErrorTrait + Send + Sync + 'static
422	{
423		match self {
424			Ok(value) => { Ok(value) }
425			Err(prev_err) => { Err(prev_err.raise(err())) }
426		}
427	}
428}
429
430pub trait ResultManyExt {
431	type Ok;
432	type Err;
433
434	fn or_raise<E>(self, err: impl FnOnce() -> E) -> Result<Self::Ok, Err<E>>
435	where
436		E: ErrorTrait + Send + Sync + 'static;
437}
438
439impl<T, E> ResultManyExt for Result<T, Vec<E>>
440where
441	E: ErrorTrait + Send + Sync + 'static
442{
443	type Ok = T;
444	type Err = E;
445
446	#[inline]
447	#[track_caller]
448	fn or_raise<E2>(self, err: impl FnOnce() -> E2) -> Result<T, Err<E2>>
449	where
450		E2: ErrorTrait + Send + Sync + 'static
451	{
452		match self {
453			Ok(value) => { Ok(value) }
454			Err(errors) => { Err(Err::from_errs(err(), &mut errors.into_iter())) }
455		}
456	}
457}
458
459impl<T, E> ResultManyExt for Result<T, Vec<Err<E>>>
460where
461	E: ErrorTrait + Send + Sync + 'static
462{
463	type Ok = T;
464	type Err = E;
465
466	#[inline]
467	#[track_caller]
468	fn or_raise<E2>(self, err: impl FnOnce() -> E2) -> Result<T, Err<E2>>
469	where
470		E2: ErrorTrait + Send + Sync + 'static
471	{
472		match self {
473			Ok(value) => { Ok(value) }
474			Err(errors) => {
475				let mut errors = errors
476					.into_iter()
477					.map(Err::into_error);
478
479				Err(Err::from_errs(err(), &mut errors))
480			}
481		}
482	}
483}
484
485impl<T, E> ResultManyExt for Result<T, &[E]>
486where
487	E: ErrorTrait + Clone + Send + Sync + 'static
488{
489	type Ok = T;
490	type Err = E;
491
492	#[inline]
493	#[track_caller]
494	fn or_raise<E2>(self, err: impl FnOnce() -> E2) -> Result<T, Err<E2>>
495	where
496		E2: ErrorTrait + Send + Sync + 'static
497	{
498		match self {
499			Ok(value) => { Ok(value) }
500			Err(errors) => { Err(Err::from_errs(err(), &mut errors.iter().cloned())) }
501		}
502	}
503}
504
505impl<T, E, const N: usize> ResultManyExt for Result<T, [E; N]>
506where
507	E: ErrorTrait + Send + Sync + 'static
508{
509	type Ok = T;
510	type Err = E;
511
512	#[inline]
513	#[track_caller]
514	fn or_raise<E2>(self, err: impl FnOnce() -> E2) -> Result<T, Err<E2>>
515	where
516		E2: ErrorTrait + Send + Sync + 'static
517	{
518		match self {
519			Ok(value) => { Ok(value) }
520			Err(errors) => { Err(Err::from_errs(err(), &mut errors.into_iter())) }
521		}
522	}
523}
524
525impl<T, E, const N: usize> ResultManyExt for Result<T, [Err<E>; N]>
526where
527	E: ErrorTrait + Send + Sync + 'static
528{
529	type Ok = T;
530	type Err = E;
531
532	#[inline]
533	#[track_caller]
534	fn or_raise<E2>(self, err: impl FnOnce() -> E2) -> Result<T, Err<E2>>
535	where
536		E2: ErrorTrait + Send + Sync + 'static
537	{
538		match self {
539			Ok(value) => { Ok(value) }
540			Err(errors) => {
541				let mut errors = errors
542					.into_iter()
543					.map(Err::into_error);
544
545				Err(Err::from_errs(err(), &mut errors))
546			}
547		}
548	}
549}
550
551#[doc(hidden)]
552pub mod __proc_macro_support {
553	pub use core::error::Error;
554	pub use core::fmt::{ Debug, Display };
555	pub use displaydoc::Display;
556}