grafix_toolbox/kit/policies/func/
result.rs1use 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}