Skip to main content

malachite_base/unions/
random.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::num::random::{RandomUnsignedRange, random_unsigned_range};
10use crate::random::Seed;
11use crate::unions::Union2;
12
13/// Defines random union generators.
14///
15/// Malachite provides [`random_union2s`], but you can also define `random_union3s`,
16/// `random_union4s`, and so on, in your program using the code below. The documentation for
17/// [`random_union2s`] describes these other functions as well.
18///
19/// See usage examples [here](self#random_union2s).
20///
21/// ```
22/// use malachite_base::num::random::{random_unsigned_range, RandomUnsignedRange};
23/// use malachite_base::random::Seed;
24/// use malachite_base::unions::UnionFromStrError;
25/// use malachite_base::{random_unions, union_struct};
26/// use std::fmt::{self, Display, Formatter};
27/// use std::str::FromStr;
28///
29/// union_struct!(
30///     (pub(crate)),
31///     Union3,
32///     Union3<T, T, T>,
33///     [A, A, 'A', a],
34///     [B, B, 'B', b],
35///     [C, C, 'C', c]
36/// );
37/// union_struct!(
38///     (pub(crate)),
39///     Union4,
40///     Union4<T, T, T, T>,
41///     [A, A, 'A', a],
42///     [B, B, 'B', b],
43///     [C, C, 'C', c],
44///     [D, D, 'D', d]
45/// );
46/// union_struct!(
47///     (pub(crate)),
48///     Union5,
49///     Union5<T, T, T, T, T>,
50///     [A, A, 'A', a],
51///     [B, B, 'B', b],
52///     [C, C, 'C', c],
53///     [D, D, 'D', d],
54///     [E, E, 'E', e]
55/// );
56/// union_struct!(
57///     (pub(crate)),
58///     Union6,
59///     Union6<T, T, T, T, T, T>,
60///     [A, A, 'A', a],
61///     [B, B, 'B', b],
62///     [C, C, 'C', c],
63///     [D, D, 'D', d],
64///     [E, E, 'E', e],
65///     [F, F, 'F', f]
66/// );
67/// union_struct!(
68///     (pub(crate)),
69///     Union7,
70///     Union7<T, T, T, T, T, T, T>,
71///     [A, A, 'A', a],
72///     [B, B, 'B', b],
73///     [C, C, 'C', c],
74///     [D, D, 'D', d],
75///     [E, E, 'E', e],
76///     [F, F, 'F', f],
77///     [G, G, 'G', g]
78/// );
79/// union_struct!(
80///     (pub(crate)),
81///     Union8,
82///     Union8<T, T, T, T, T, T, T, T>,
83///     [A, A, 'A', a],
84///     [B, B, 'B', b],
85///     [C, C, 'C', c],
86///     [D, D, 'D', d],
87///     [E, E, 'E', e],
88///     [F, F, 'F', f],
89///     [G, G, 'G', g],
90///     [H, H, 'H', h]
91/// );
92///
93/// random_unions!(
94///     (pub(crate)),
95///     Union3,
96///     RandomUnion3s,
97///     random_union3s,
98///     3,
99///     [0, X, I, A, xs, xs_gen],
100///     [1, Y, J, B, ys, ys_gen],
101///     [2, Z, K, C, zs, zs_gen]
102/// );
103/// random_unions!(
104///     (pub(crate)),
105///     Union4,
106///     RandomUnion4s,
107///     random_union4s,
108///     4,
109///     [0, X, I, A, xs, xs_gen],
110///     [1, Y, J, B, ys, ys_gen],
111///     [2, Z, K, C, zs, zs_gen],
112///     [3, W, L, D, ws, ws_gen]
113/// );
114/// random_unions!(
115///     (pub(crate)),
116///     Union5,
117///     RandomUnion5s,
118///     random_union5s,
119///     5,
120///     [0, X, I, A, xs, xs_gen],
121///     [1, Y, J, B, ys, ys_gen],
122///     [2, Z, K, C, zs, zs_gen],
123///     [3, W, L, D, ws, ws_gen],
124///     [4, V, M, E, vs, vs_gen]
125/// );
126/// random_unions!(
127///     (pub(crate)),
128///     Union6,
129///     RandomUnion6s,
130///     random_union6s,
131///     6,
132///     [0, X, I, A, xs, xs_gen],
133///     [1, Y, J, B, ys, ys_gen],
134///     [2, Z, K, C, zs, zs_gen],
135///     [3, W, L, D, ws, ws_gen],
136///     [4, V, M, E, vs, vs_gen],
137///     [5, U, N, F, us, us_gen]
138/// );
139/// random_unions!(
140///     (pub(crate)),
141///     Union7,
142///     RandomUnion7s,
143///     random_union7s,
144///     7,
145///     [0, X, I, A, xs, xs_gen],
146///     [1, Y, J, B, ys, ys_gen],
147///     [2, Z, K, C, zs, zs_gen],
148///     [3, W, L, D, ws, ws_gen],
149///     [4, V, M, E, vs, vs_gen],
150///     [5, U, N, F, us, us_gen],
151///     [6, T, O, G, ts, ts_gen]
152/// );
153/// random_unions!(
154///     (pub(crate)),
155///     Union8,
156///     RandomUnion8s,
157///     random_union8s,
158///     8,
159///     [0, X, I, A, xs, xs_gen],
160///     [1, Y, J, B, ys, ys_gen],
161///     [2, Z, K, C, zs, zs_gen],
162///     [3, W, L, D, ws, ws_gen],
163///     [4, V, M, E, vs, vs_gen],
164///     [5, U, N, F, us, us_gen],
165///     [6, T, O, G, ts, ts_gen],
166///     [7, S, P, H, ss, ss_gen]
167/// );
168/// ```
169#[macro_export]
170macro_rules! random_unions {
171    (
172        ($($vis:tt)*),
173        $union: ident,
174        $random_struct: ident,
175        $random_fn: ident,
176        $n: expr,
177        $([$i: expr, $t: ident, $it: ident, $variant: ident, $xs: ident, $xs_gen: ident]),*
178    ) => {
179        /// This documentation applies not only to `RandomUnion2s`, but also to `RandomUnion3s`,
180        /// `RandomUnion4s`, and so on. See [`random_unions`] for more information.
181        ///
182        /// Generates random $n$-unions with elements from $n$ iterators.
183        #[derive(Clone, Debug)]
184        $($vis)* struct $random_struct<$($t, $it: Iterator<Item=$t>),*> {
185            indices: RandomUnsignedRange<usize>,
186            $($xs: $it,)*
187        }
188
189        impl<$($t, $it: Iterator<Item=$t>),*> Iterator for $random_struct<$($t, $it),*> {
190            type Item = $union<$($t),*>;
191
192            fn next(&mut self) -> Option<Self::Item> {
193                match self.indices.next().unwrap() {
194                    $($i => self.$xs.next().map($union::$variant),)*
195                    _ => unreachable!(),
196                }
197            }
198        }
199
200        /// This documentation applies not only to `random_union2s`, but also to `random_union3s`,
201        /// `random_union4s`, and so on. See [`random_unions`] for more information.
202        ///
203        /// Generates random $n$-unions with elements from $n$ iterators.
204        ///
205        /// The probability of a particular $n$-union being generated is the probability of its
206        /// element divided by $n$.
207        ///
208        /// `xs`, `ys`, `zs`, ... must be infinite.
209        ///
210        /// # Examples
211        /// See [here](self#random_union2s).
212        $($vis)* fn $random_fn<$($t, $it: Iterator<Item=$t>),*>(
213            seed: Seed, $($xs_gen: &dyn Fn(Seed) -> $it),*
214        ) -> $random_struct<$($t, $it),*> {
215            $random_struct {
216                indices: random_unsigned_range(seed.fork("indices"), 0, $n),
217                $($xs: $xs_gen(seed.fork(stringify!($xs))),)*
218            }
219        }
220    }
221}
222random_unions!(
223    (pub),
224    Union2,
225    RandomUnion2s,
226    random_union2s,
227    2,
228    [0, X, I, A, xs, xs_gen],
229    [1, Y, J, B, ys, ys_gen]
230);