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