error_accumulator/
construct.rs

1//! Helper traits to enable some of this crate's type magic.
2
3use std::{convert::Infallible, error::Error};
4
5use crate::cons::{AsRefTuple, Cons, Nil};
6
7/// Marker trait for types that can turn a list of values into something else.
8///
9/// This is used for `on_ok()` methods so the provided closures can take each
10/// recorded value as separate argument instead of deconstructing tuples.
11///
12/// There are default implementations for [`FnMut`] closures with up to 10
13/// arguments.
14pub trait Constructor<In, Out> {
15    /// Take the input and convert it into output.
16    fn construct(self, input: In) -> Out;
17}
18
19/// Marker trait for types that can validate a list of values into something
20/// potentially fallible.
21///
22/// There are default implementations for [`FnMut`] closures with up to 10
23/// reference arguments.
24pub trait ListValidator<List, Out, Err> {
25    /// Transform an input. May fails doing so.
26    fn validate(self, values: &List) -> Result<Out, Err>;
27}
28
29impl<Out, F> Constructor<(), Out> for F
30where
31    F: FnMut() -> Out,
32{
33    fn construct(mut self, _: ()) -> Out {
34        self()
35    }
36}
37
38impl<A, Out, F> Constructor<(A,), Out> for F
39where
40    F: FnMut(A) -> Out,
41{
42    fn construct(mut self, (a,): (A,)) -> Out {
43        self(a)
44    }
45}
46
47macro_rules! impl_constructor {
48    ($($elem:ident),+) => {
49        impl< $( $elem ),+ , Out, Func> Constructor<($( $elem ),+), Out> for Func
50        where
51            Func: FnMut( $( $elem ),+ ) -> Out,
52        {
53            #[allow(non_snake_case)]
54            fn construct(mut self, ( $( $elem ),+ ): ( $( $elem ),+ )) -> Out {
55                self( $( $elem ),+ )
56            }
57        }
58    };
59}
60
61impl_constructor!(A, B);
62impl_constructor!(A, B, C);
63impl_constructor!(A, B, C, D);
64impl_constructor!(A, B, C, D, E);
65impl_constructor!(A, B, C, D, E, F);
66impl_constructor!(A, B, C, D, E, F, G);
67impl_constructor!(A, B, C, D, E, F, G, H);
68impl_constructor!(A, B, C, D, E, F, G, H, I);
69impl_constructor!(A, B, C, D, E, F, G, H, I, J);
70impl_constructor!(A, B, C, D, E, F, G, H, I, J, K);
71impl_constructor!(A, B, C, D, E, F, G, H, I, J, K, L);
72
73impl<Out, Func> ListValidator<Nil, Out, Infallible> for Func
74where
75    Func: FnMut() -> Result<Out, Infallible>,
76{
77    fn validate(mut self, _: &Nil) -> Result<Out, Infallible> {
78        self()
79    }
80}
81
82impl<A, Out, Err, Func> ListValidator<Cons<A, Nil>, Out, Err> for Func
83where
84    Func: for<'a> FnMut(&'a A) -> Result<Out, Err>,
85    Err: Error + Send + Sync + 'static,
86{
87    fn validate(mut self, values: &Cons<A, Nil>) -> Result<Out, Err> {
88        let (a,) = values.as_unwraped_tuple();
89        self(a)
90    }
91}
92
93macro_rules! list_type {
94    ($head:ident, $($tail:ident),*) => {
95        Cons< $head, list_type!( $( $tail ),* ) >
96    };
97    ($head:ident) => {
98        Cons< $head, Nil >
99    };
100    () => {
101        Nil
102    };
103}
104
105macro_rules! impl_validator {
106    ($($elem:ident),+) => {
107        impl<$( $elem ),+ , Out, Err, Func> ListValidator<list_type!( $( $elem ),+ ), Out, Err> for Func
108        where
109            Func: for<'a> FnMut( $( &'a $elem ),+ ) -> Result<Out, Err>,
110            Err: Error + Send + Sync + 'static,
111        {
112            #[allow(non_snake_case)]
113            fn validate(mut self, values: & list_type!( $( $elem ),+ )) -> Result<Out, Err> {
114                let ( $( $elem ),+ ) = $crate::cons::AsRefTuple::as_unwraped_tuple(values);
115                self( $( $elem ),+ )
116            }
117        }
118    };
119}
120
121impl_validator!(A, B);
122impl_validator!(A, B, C);
123impl_validator!(A, B, C, D);
124impl_validator!(A, B, C, D, E);
125impl_validator!(A, B, C, D, E, F);
126impl_validator!(A, B, C, D, E, F, G);
127impl_validator!(A, B, C, D, E, F, G, H);
128impl_validator!(A, B, C, D, E, F, G, H, I);
129impl_validator!(A, B, C, D, E, F, G, H, I, J);
130impl_validator!(A, B, C, D, E, F, G, H, I, J, K);
131impl_validator!(A, B, C, D, E, F, G, H, I, J, K, L);