Skip to main content

hegel/generators/
tuples.rs

1use super::{BasicGenerator, DefaultGenerator, Generator, TestCase, labels};
2use crate::cbor_utils::{cbor_array, cbor_map};
3use ciborium::Value;
4use std::marker::PhantomData;
5
6/// Creates a tuple generator from 0–12 component generators.
7///
8/// # Examples
9///
10/// ```no_run
11/// use hegel::generators as gs;
12/// use hegel::tuples;
13///
14/// // 0-tuple (unit)
15/// let gen0 = tuples!();
16///
17/// // 1-tuple
18/// let gen1 = tuples!(gs::integers::<i32>());
19///
20/// // 2-tuple
21/// let gen2 = tuples!(gs::integers::<i32>(), gs::booleans());
22///
23/// // 3-tuple
24/// let gen3 = tuples!(gs::integers::<i32>(), gs::booleans(), gs::text());
25/// ```
26#[macro_export]
27macro_rules! tuples {
28    () => {
29        $crate::generators::tuples0()
30    };
31    ($g1:expr $(,)?) => {
32        $crate::generators::tuples1($g1)
33    };
34    ($g1:expr, $g2:expr $(,)?) => {
35        $crate::generators::tuples2($g1, $g2)
36    };
37    ($g1:expr, $g2:expr, $g3:expr $(,)?) => {
38        $crate::generators::tuples3($g1, $g2, $g3)
39    };
40    ($g1:expr, $g2:expr, $g3:expr, $g4:expr $(,)?) => {
41        $crate::generators::tuples4($g1, $g2, $g3, $g4)
42    };
43    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr $(,)?) => {
44        $crate::generators::tuples5($g1, $g2, $g3, $g4, $g5)
45    };
46    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr $(,)?) => {
47        $crate::generators::tuples6($g1, $g2, $g3, $g4, $g5, $g6)
48    };
49    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr, $g7:expr $(,)?) => {
50        $crate::generators::tuples7($g1, $g2, $g3, $g4, $g5, $g6, $g7)
51    };
52    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr, $g7:expr, $g8:expr $(,)?) => {
53        $crate::generators::tuples8($g1, $g2, $g3, $g4, $g5, $g6, $g7, $g8)
54    };
55    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr, $g7:expr, $g8:expr, $g9:expr $(,)?) => {
56        $crate::generators::tuples9($g1, $g2, $g3, $g4, $g5, $g6, $g7, $g8, $g9)
57    };
58    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr, $g7:expr, $g8:expr, $g9:expr, $g10:expr $(,)?) => {
59        $crate::generators::tuples10($g1, $g2, $g3, $g4, $g5, $g6, $g7, $g8, $g9, $g10)
60    };
61    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr, $g7:expr, $g8:expr, $g9:expr, $g10:expr, $g11:expr $(,)?) => {
62        $crate::generators::tuples11($g1, $g2, $g3, $g4, $g5, $g6, $g7, $g8, $g9, $g10, $g11)
63    };
64    ($g1:expr, $g2:expr, $g3:expr, $g4:expr, $g5:expr, $g6:expr, $g7:expr, $g8:expr, $g9:expr, $g10:expr, $g11:expr, $g12:expr $(,)?) => {
65        $crate::generators::tuples12(
66            $g1, $g2, $g3, $g4, $g5, $g6, $g7, $g8, $g9, $g10, $g11, $g12,
67        )
68    };
69}
70
71macro_rules! impl_tuple {
72    ($name:ident, $fn_name:ident, $(($idx:tt, $field:ident, $G:ident, $T:ident)),+) => {
73        pub struct $name<$($G,)+ $($T,)+> {
74            $($field: $G,)+
75            _phantom: PhantomData<fn($($T,)+)>,
76        }
77
78        impl<$($T,)+ $($G,)+> Generator<($($T,)+)> for $name<$($G,)+ $($T,)+>
79        where
80            $($G: Generator<$T>,)+
81        {
82            fn do_draw(&self, tc: &TestCase) -> ($($T,)+) {
83                if let Some(basic) = self.as_basic() {
84                    basic.do_draw(tc)
85                } else {
86                    // nocov start
87                    tc.start_span(labels::TUPLE);
88                    let result = ($(self.$field.do_draw(tc),)+);
89                    tc.stop_span(false);
90                    result
91                    // nocov end
92                }
93            }
94
95            fn as_basic(&self) -> Option<BasicGenerator<'_, ($($T,)+)>> {
96                $(let $field = self.$field.as_basic()?;)+
97
98                let schema = cbor_map! {
99                    "type" => "tuple",
100                    "elements" => cbor_array![$($field.schema().clone()),+]
101                };
102
103                Some(BasicGenerator::new(schema, move |raw| {
104                    let arr = match raw {
105                        Value::Array(arr) => arr,
106                        _ => panic!("Expected array from tuple schema, got {:?}", raw), // nocov
107                    };
108                    let mut iter = arr.into_iter();
109
110                    ($($field.parse_raw(iter.next().expect(concat!("tuple missing element ", stringify!($idx)))),)+)
111                }))
112            }
113        }
114
115        #[doc(hidden)]
116        #[allow(clippy::too_many_arguments)]
117        pub fn $fn_name<$($T,)+ $($G: Generator<$T>,)+>(
118            $($field: $G,)+
119        ) -> $name<$($G,)+ $($T,)+> {
120            $name {
121                $($field,)+
122                _phantom: PhantomData,
123            }
124        }
125
126        impl<$($T: DefaultGenerator + 'static,)+> DefaultGenerator for ($($T,)+)
127        where
128            $(<$T as DefaultGenerator>::Generator: Send + Sync,)+
129        {
130            type Generator = $name<$(<$T as DefaultGenerator>::Generator,)+ $($T,)+>;
131            fn default_generator() -> Self::Generator {
132                $fn_name($(<$T>::default_generator(),)+)
133            }
134        }
135    };
136}
137
138/// Generator for the unit type `()`. Created by [`tuples0()`].
139pub struct Tuple0Generator;
140
141impl Generator<()> for Tuple0Generator {
142    fn do_draw(&self, _tc: &TestCase) {}
143}
144
145#[doc(hidden)]
146pub fn tuples0() -> Tuple0Generator {
147    Tuple0Generator
148}
149
150impl DefaultGenerator for () {
151    type Generator = Tuple0Generator;
152    fn default_generator() -> Self::Generator {
153        tuples0()
154    }
155}
156
157impl_tuple!(Tuple1Generator, tuples1, (0, gen1, G1, T1));
158impl_tuple!(
159    Tuple2Generator,
160    tuples2,
161    (0, gen1, G1, T1),
162    (1, gen2, G2, T2)
163);
164impl_tuple!(
165    Tuple3Generator,
166    tuples3,
167    (0, gen1, G1, T1),
168    (1, gen2, G2, T2),
169    (2, gen3, G3, T3)
170);
171impl_tuple!(
172    Tuple4Generator,
173    tuples4,
174    (0, gen1, G1, T1),
175    (1, gen2, G2, T2),
176    (2, gen3, G3, T3),
177    (3, gen4, G4, T4)
178);
179impl_tuple!(
180    Tuple5Generator,
181    tuples5,
182    (0, gen1, G1, T1),
183    (1, gen2, G2, T2),
184    (2, gen3, G3, T3),
185    (3, gen4, G4, T4),
186    (4, gen5, G5, T5)
187);
188impl_tuple!(
189    Tuple6Generator,
190    tuples6,
191    (0, gen1, G1, T1),
192    (1, gen2, G2, T2),
193    (2, gen3, G3, T3),
194    (3, gen4, G4, T4),
195    (4, gen5, G5, T5),
196    (5, gen6, G6, T6)
197);
198impl_tuple!(
199    Tuple7Generator,
200    tuples7,
201    (0, gen1, G1, T1),
202    (1, gen2, G2, T2),
203    (2, gen3, G3, T3),
204    (3, gen4, G4, T4),
205    (4, gen5, G5, T5),
206    (5, gen6, G6, T6),
207    (6, gen7, G7, T7)
208);
209impl_tuple!(
210    Tuple8Generator,
211    tuples8,
212    (0, gen1, G1, T1),
213    (1, gen2, G2, T2),
214    (2, gen3, G3, T3),
215    (3, gen4, G4, T4),
216    (4, gen5, G5, T5),
217    (5, gen6, G6, T6),
218    (6, gen7, G7, T7),
219    (7, gen8, G8, T8)
220);
221impl_tuple!(
222    Tuple9Generator,
223    tuples9,
224    (0, gen1, G1, T1),
225    (1, gen2, G2, T2),
226    (2, gen3, G3, T3),
227    (3, gen4, G4, T4),
228    (4, gen5, G5, T5),
229    (5, gen6, G6, T6),
230    (6, gen7, G7, T7),
231    (7, gen8, G8, T8),
232    (8, gen9, G9, T9)
233);
234impl_tuple!(
235    Tuple10Generator,
236    tuples10,
237    (0, gen1, G1, T1),
238    (1, gen2, G2, T2),
239    (2, gen3, G3, T3),
240    (3, gen4, G4, T4),
241    (4, gen5, G5, T5),
242    (5, gen6, G6, T6),
243    (6, gen7, G7, T7),
244    (7, gen8, G8, T8),
245    (8, gen9, G9, T9),
246    (9, gen10, G10, T10)
247);
248impl_tuple!(
249    Tuple11Generator,
250    tuples11,
251    (0, gen1, G1, T1),
252    (1, gen2, G2, T2),
253    (2, gen3, G3, T3),
254    (3, gen4, G4, T4),
255    (4, gen5, G5, T5),
256    (5, gen6, G6, T6),
257    (6, gen7, G7, T7),
258    (7, gen8, G8, T8),
259    (8, gen9, G9, T9),
260    (9, gen10, G10, T10),
261    (10, gen11, G11, T11)
262);
263impl_tuple!(
264    Tuple12Generator,
265    tuples12,
266    (0, gen1, G1, T1),
267    (1, gen2, G2, T2),
268    (2, gen3, G3, T3),
269    (3, gen4, G4, T4),
270    (4, gen5, G5, T5),
271    (5, gen6, G6, T6),
272    (6, gen7, G7, T7),
273    (7, gen8, G8, T8),
274    (8, gen9, G9, T9),
275    (9, gen10, G10, T10),
276    (10, gen11, G11, T11),
277    (11, gen12, G12, T12)
278);