Skip to main content

grafix_toolbox/kit/policies/func/
result.rs

1use crate::lib::*;
2
3pub type Res<T> = Result<T, String>;
4
5pub trait ExplainError<T>: Sized {
6	fn explain_err<S: Into<String>>(self, msg: impl FnOnce() -> S) -> Res<T>;
7}
8impl<T> ExplainError<T> for Option<T> {
9	fn explain_err<S: Into<String>>(self, msg: impl FnOnce() -> S) -> Res<T> {
10		self.map_or_else(|| [&msg().into(), ": is None"].concat().pipe(Err), Ok)
11	}
12}
13impl<T, E: Display> ExplainError<T> for Result<T, E> {
14	fn explain_err<S: Into<String>>(self, msg: impl FnOnce() -> S) -> Res<T> {
15		self.map_err(|e| [msg().into(), format!(":\n{e}")].concat())
16	}
17}
18
19pub trait FlattenError<T> {
20	fn chain_err(self) -> Res<T>;
21}
22impl<T, E: Display> FlattenError<T> for Result<Option<T>, E> {
23	fn chain_err(self) -> Res<T> {
24		self.res().and_then(|o| o.res())
25	}
26}
27impl<T, E: Display> FlattenError<T> for Option<Result<T, E>> {
28	fn chain_err(self) -> Res<T> {
29		self.res().and_then(|o| o.res())
30	}
31}
32impl<T, E1: Display, E2: Display> FlattenError<T> for Result<Result<T, E1>, E2> {
33	fn chain_err(self) -> Res<T> {
34		self.res().and_then(|o| o.res())
35	}
36}
37
38pub trait ThreadUnwrap<T> {
39	fn join_fail<S: Into<String>>(self, explanation: impl FnOnce() -> S) -> T;
40	fn join_res(self) -> Res<T>;
41}
42impl<T> ThreadUnwrap<T> for JoinHandle<T> {
43	fn join_fail<S: Into<String>>(self, ex: impl FnOnce() -> S) -> T {
44		self.join()
45			.map_err(|e| {
46				PRINT!(ex().into());
47				std::panic::resume_unwind(e)
48			})
49			.valid()
50	}
51	fn join_res(self) -> Res<T> {
52		let (id, name) = self.thread().pipe(|t| (t.id(), t.name().unwrap_or("???").to_string()));
53		self.join().map_err(|_| format!("Thread {name:?}<{}>({id:?}) panicked", type_name::<T>()))
54	}
55}
56impl<T, E: Display> ThreadUnwrap<T> for Result<JoinHandle<T>, E> {
57	fn join_fail<S: Into<String>>(self, e: impl FnOnce() -> S) -> T {
58		match self {
59			Ok(s) => s.join_fail(e),
60			err @ Err(_) => {
61				err.explain_err(e).fail();
62				unreachable!()
63			}
64		}
65	}
66	fn join_res(self) -> Res<T> {
67		self.res()?.join_res()
68	}
69}
70
71pub trait UniformUnwrap<T>: Sized {
72	fn res(self) -> Res<T>;
73	fn uni_is_err(&self) -> bool;
74	fn uni_or_else(self, op: impl FnOnce(&str) -> T) -> T;
75	fn fail(self) -> T {
76		self.uni_or_else(|e| ERROR!(e))
77	}
78	#[inline(always)]
79	fn sink(self) {}
80}
81impl<T> UniformUnwrap<T> for Option<T> {
82	fn res(self) -> Res<T> {
83		self.ok_or_else(|| "Is None".into())
84	}
85	fn uni_is_err(&self) -> bool {
86		self.is_none()
87	}
88	fn uni_or_else(self, op: impl FnOnce(&str) -> T) -> T {
89		self.unwrap_or_else(|| op("Is None"))
90	}
91}
92impl<T, R: Display> UniformUnwrap<T> for Result<T, R> {
93	fn res(self) -> Res<T> {
94		self.map_err(|e| {
95			let t = type_name::<T>();
96			if "String" == t { e.to_string() } else { format!("{t}: {e}") }
97		})
98	}
99	fn uni_is_err(&self) -> bool {
100		self.is_err()
101	}
102	fn uni_or_else(self, op: impl FnOnce(&str) -> T) -> T {
103		self.unwrap_or_else(|e| op(&e.to_string()))
104	}
105}
106
107pub trait UniformUnwrapOrDefault<T: Default>: UniformUnwrap<T> {
108	fn uni_err(self) -> (T, String);
109	fn warn(self) -> T;
110}
111impl<T: Default> UniformUnwrapOrDefault<T> for Option<T> {
112	fn uni_err(self) -> (T, String) {
113		(T::default(), "Is None".into())
114	}
115	fn warn(self) -> T {
116		self.unwrap_or_else(|| FAIL!({ T::default() }, "Is None"))
117	}
118}
119impl<T: Default, R: Display> UniformUnwrapOrDefault<T> for Result<T, R> {
120	fn uni_err(self) -> (T, String) {
121		(T::default(), self.err().valid().to_string())
122	}
123	fn warn(self) -> T {
124		self.map_err(|e| FAIL!(e)).unwrap_or_default()
125	}
126}