Skip to main content

cba/
bait.rs

1use std::fmt::Display;
2
3use crate::StringError;
4
5#[easy_ext::ext(MaybeExt)]
6pub impl<T> T
7where
8    T: Sized,
9{
10    /// Merge from maybe by taking.
11    fn _take(&mut self, maybe: Option<T>) {
12        if let Some(v) = maybe {
13            *self = v;
14        }
15    }
16
17    /// Merge from maybe by cloning.
18    fn _clone(&mut self, maybe: &Option<T>) -> T
19    where
20        T: Clone,
21    {
22        if let Some(v) = maybe {
23            *self = v.clone();
24        }
25        self.clone()
26    }
27}
28
29// this would be more useful if try blocks exposed their "other" type so we could call into on e
30#[easy_ext::ext(ResultExt)]
31pub impl<T, E> Result<T, E> {
32    /// cast result types.
33    ///
34    /// # Note
35    /// Difficult to used with ?, more useful in return statements.
36    #[inline]
37    fn cast<F, S>(self) -> Result<S, F>
38    where
39        F: From<E>,
40        S: From<T>,
41    {
42        match self {
43            Ok(s) => Ok(s.into()),
44            Err(e) => Err(e.into()),
45        }
46    }
47
48    /// cast result to StringError.
49    #[inline]
50    fn cast_(self) -> Result<T, StringError>
51    where
52        E: Display,
53    {
54        match self {
55            Ok(s) => Ok(s),
56            Err(e) => Err(e.to_string().into()),
57        }
58    }
59
60    // debated between prefix and prefix_err, chose the first because anyhow just calls it context.
61    /// Convert Err(e) to the string '{prefix}: {e}'
62    #[inline]
63    fn prefix(self, prefix: impl Display) -> Result<T, StringError>
64    where
65        E: std::fmt::Display,
66    {
67        match self {
68            Ok(val) => Ok(val),
69            Err(e) => Err(format!("{prefix}: {e}").into()),
70        }
71    }
72
73    // logging
74
75    /// Log the error.
76    ///
77    /// # Notes
78    /// Can be used in conjunction with [`prefix`](ResultExt::prefix) to add context.
79    /// See also: [`crate::bog::BogOkExt`] to bog instead of log.
80    #[inline]
81    fn elog(self) -> Result<T, E>
82    where
83        E: Display,
84    {
85        self.map_err(|e| {
86            log::error!("{e}");
87            e
88        })
89    }
90
91    /// [`elog`](ResultExt::elog), then consume the error.
92    ///
93    /// # Notes
94    /// Can be used in conjunction with [`prefix`](ResultExt::prefix) to add context.
95    /// See also: [`crate::bog::BogOkExt`] to bog instead of log.
96    #[inline]
97    fn _elog(self) -> Option<T>
98    where
99        E: Display,
100    {
101        match self {
102            Ok(x) => Some(x),
103            Err(e) => {
104                log::error!("{e}");
105                None
106            }
107        }
108    }
109
110    /// Log the error as a warning.
111    ///
112    /// # Notes
113    /// Can be used in conjunction with [`prefix`](ResultExt::prefix) to add context.
114    /// See also: [`crate::bog::BogOkExt`] to bog instead of log.
115    #[inline]
116    fn wlog(self) -> Result<T, E>
117    where
118        E: Display,
119    {
120        self.map_err(|e| {
121            log::warn!("{e}");
122            e
123        })
124    }
125
126    /// [`wlog`](ResultExt::wlog), then consume the error.
127    ///
128    /// # Notes
129    /// Can be used in conjunction with [`prefix`](ResultExt::prefix) to add context.
130    /// See also: [`crate::bog::BogOkExt`] to bog instead of log.
131    #[inline]
132    fn _wlog(self) -> Option<T>
133    where
134        E: Display,
135    {
136        match self {
137            Ok(x) => Some(x),
138            Err(e) => {
139                log::warn!("{e}");
140                None
141            }
142        }
143    }
144}
145
146#[easy_ext::ext(OptionExt)]
147pub impl<T> Option<T> {
148    /// Unwrap or exit
149    fn or_exit(self) -> T {
150        match self {
151            Some(val) => val,
152            None => {
153                std::process::exit(1);
154            }
155        }
156    }
157
158    /// Unwrap or log and exit
159    fn _elog(self, s: &str) -> T {
160        if self.is_none() {
161            log::error!("{s}");
162        }
163        self.or_exit()
164    }
165
166    /// Log the error if None, then transform to a Result.
167    fn elog<E: Display>(self, err: E) -> Result<T, E> {
168        match self {
169            Some(v) => Ok(v),
170            None => {
171                log::error!("{err}");
172                Err(err)
173            }
174        }
175    }
176
177    /// Log the error as a warning if None, then transform to a Result.
178    fn wlog<E: Display>(self, err: E) -> Result<T, E> {
179        match self {
180            Some(v) => Ok(v),
181            None => {
182                log::warn!("{err}");
183                Err(err)
184            }
185        }
186    }
187}
188
189#[easy_ext::ext(BoolExt)]
190pub impl bool {
191    #[inline]
192    fn ternary<U>(&self, and: U, or: U) -> U {
193        self.then_some(and).unwrap_or(or)
194    }
195
196    #[inline]
197    fn and_then<U>(&self, f: impl FnOnce() -> Option<U>) -> Option<U> {
198        if *self { f() } else { None }
199    }
200
201    #[inline]
202    fn neg(&self) -> Self {
203        !*self
204    }
205
206    #[inline]
207    fn or_exit(&self) {
208        if !self {
209            std::process::exit(1)
210        }
211    }
212}
213
214// ---------------------------------
215
216use std::sync::{Mutex, MutexGuard};
217#[easy_ext::ext(MutexExt)]
218pub impl<T> Mutex<T> {
219    fn _lock(&self) -> MutexGuard<'_, T> {
220        match self.lock() {
221            Ok(g) => g,
222            Err(poisoned) => poisoned.into_inner(),
223        }
224    }
225}
226
227// ---------------------------------
228
229#[easy_ext::ext(TransformExt)]
230pub impl<T> T {
231    fn transform<Q>(self, transform: impl FnOnce(Self) -> Q) -> Q
232    where
233        T: Sized,
234    {
235        transform(self)
236    }
237
238    /// # Example
239    ///
240    /// ```rust,ignore
241    /// Table::new(rows, widths.to_vec())
242    ///     .block(block)
243    ///     .transform_if(
244    ///         true,
245    ///         |t| t.style(style),
246    ///     )
247    ///```
248    fn transform_if(self, condition: bool, transform: impl FnOnce(Self) -> Self) -> Self
249    where
250        T: Sized,
251    {
252        if condition { transform(self) } else { self }
253    }
254
255    fn modify<Q>(mut self, modify: impl FnOnce(&mut Self) -> Q) -> Self
256    where
257        T: Sized,
258    {
259        modify(&mut self);
260        self
261    }
262
263    /// # Example
264    ///
265    /// ```rust
266    /// use cba::bait::TransformExt;
267    ///
268    /// true.modify_if(cfg!(debug_assertions), |x| *dbg!(x));
269    ///```
270    fn modify_if<Q>(mut self, condition: bool, modify: impl FnOnce(&mut Self) -> Q) -> Self
271    where
272        T: Sized,
273    {
274        if condition {
275            modify(&mut self);
276        }
277        self
278    }
279
280    /// # Example
281    ///
282    /// ```rust
283    /// use cba::bait::TransformExt;
284    ///
285    /// let mut v = 0usize;
286    /// if !v.cmp_exch(&mut 0, 1) {
287    ///     unreachable!();
288    /// }
289    /// assert_eq!(v, 1);
290    ///```
291    fn cmp_exch<'a, E>(&'a mut self, expected: E, new: T) -> bool
292    where
293        &'a mut T: PartialEq<E>,
294    {
295        if self == expected {
296            *self = new;
297            true
298        } else {
299            false
300        }
301    }
302
303    /// # Example
304    ///
305    /// ```rust
306    /// use cba::bait::TransformExt;
307    ///
308    /// true.modify_if(cfg!(debug_assertions), |x| *dbg!(x));
309    ///```
310    fn cmp_replace(&mut self, new: T) -> bool
311    where
312        T: PartialEq,
313    {
314        let changed = *self != new;
315        if changed {
316            *self = new;
317        }
318        changed
319    }
320
321    fn dbg(self) -> Self
322    where
323        T: std::fmt::Debug,
324    {
325        dbg!(&self);
326        self
327    }
328}