reddish_shift/
utils.rs

1/*  utils.rs -- Useful functions, traits, types or macros
2    This file is part of <https://github.com/mahor1221/reddish-shift>.
3    Copyright (C) 2024 Mahor Foruzesh <mahor1221@gmail.com>
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <https://www.gnu.org/licenses/>.
17*/
18
19use crate::{coproduct::CoprodInjector, error::VecError};
20use frunk::Generic;
21use itertools::Itertools;
22use std::error::Error;
23
24pub trait IsDefault {
25    fn is_default(&self) -> bool;
26}
27impl<T: Default + PartialEq> IsDefault for T {
28    fn is_default(&self) -> bool {
29        *self == T::default()
30    }
31}
32
33/// Does the same thing as [frunk::from_generic]
34pub trait IntoGeneric {
35    fn into_generic<Dst>(self) -> Dst
36    where
37        Dst: Generic<Repr = Self>;
38}
39impl<Repr> IntoGeneric for Repr {
40    fn into_generic<Dst>(self) -> Dst
41    where
42        Dst: Generic<Repr = Self>,
43    {
44        <Dst as Generic>::from(self)
45    }
46}
47
48/// Copied from frunk::Coprod
49/// Display and Error implementations are added for the local Coproduct
50#[macro_export]
51macro_rules! Coprod {
52    () => { $crate::coproduct::CNil };
53    (...$Rest:ty) => { $Rest };
54    ($A:ty) => { $crate::Coprod![$A,] };
55    ($A:ty, $($tok:tt)*) => {
56        $crate::coproduct::Coproduct<$A, $crate::Coprod![$($tok)*]>
57    };
58}
59
60/// Shortcut for inject on Result types
61pub trait InjectErr<T, E> {
62    fn inject_err<F, Index>(self) -> Result<T, F>
63    where
64        Self: Sized,
65        F: CoprodInjector<E, Index>;
66}
67impl<T, E> InjectErr<T, E> for Result<T, E> {
68    #[inline(always)]
69    fn inject_err<F, Index>(self) -> Result<T, F>
70    where
71        Self: Sized,
72        F: CoprodInjector<E, Index>,
73    {
74        self.map_err(CoprodInjector::inject)
75    }
76}
77
78/// Shortcut for inject_err().map_err(..) on Result types
79#[cfg(unix_without_macos)]
80pub trait InjectMapErr<T, E> {
81    fn inject_map_err<F1, F2, O, Index>(self, f: O) -> Result<T, F2>
82    where
83        Self: Sized,
84        F1: CoprodInjector<E, Index>,
85        O: FnOnce(F1) -> F2;
86}
87
88#[cfg(unix_without_macos)]
89impl<T, E> InjectMapErr<T, E> for Result<T, E> {
90    #[inline(always)]
91    fn inject_map_err<F1, F2, O, Index>(self, f: O) -> Result<T, F2>
92    where
93        Self: Sized,
94        F1: CoprodInjector<E, Index>,
95        O: FnOnce(F1) -> F2,
96    {
97        self.map_err(|e| f(CoprodInjector::inject(e)))
98    }
99}
100
101/// Shortcut for partition_result
102pub trait CollectResult<T, E: Error> {
103    fn collect_result(self) -> Result<Vec<T>, VecError<E>>;
104}
105impl<I, T, E: Error> CollectResult<T, E> for I
106where
107    I: Itertools<Item = Result<T, E>>,
108{
109    fn collect_result(self) -> Result<Vec<T>, VecError<E>> {
110        let (v, e): (Vec<T>, Vec<E>) = self.partition_result();
111        if e.is_empty() {
112            Ok(v)
113        } else {
114            Err(VecError(e))
115        }
116    }
117}