malachite_base/unions/
exhaustive.rs

1// Copyright © 2025 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::unions::Union2;
10
11/// Defines exhaustive union generators.
12///
13/// Malachite provides [`lex_union2s`] and [`exhaustive_union2s`], but you can also define
14/// `lex_union3s`, `lex_union4s`, and so on, and `exhaustive_union3s`, `exhaustive_union4s`, and so
15/// on, in your program using the code below. The documentation for [`lex_union2s`] and
16/// [`exhaustive_union2s`] describes these other functions as well.
17///
18/// See usage examples [here](self#lex_union2s) and [here](self#exhaustive_union2s).
19///
20/// ```
21/// use malachite_base::unions::UnionFromStrError;
22/// use malachite_base::{exhaustive_unions, union_struct};
23/// use std::fmt::{self, Display, Formatter};
24/// use std::str::FromStr;
25///
26/// union_struct!(
27///     (pub(crate)),
28///     Union3,
29///     Union3<T, T, T>,
30///     [A, A, 'A', a],
31///     [B, B, 'B', b],
32///     [C, C, 'C', c]
33/// );
34/// union_struct!(
35///     (pub(crate)),
36///     Union4,
37///     Union4<T, T, T, T>,
38///     [A, A, 'A', a],
39///     [B, B, 'B', b],
40///     [C, C, 'C', c],
41///     [D, D, 'D', d]
42/// );
43/// union_struct!(
44///     (pub(crate)),
45///     Union5,
46///     Union5<T, T, T, T, T>,
47///     [A, A, 'A', a],
48///     [B, B, 'B', b],
49///     [C, C, 'C', c],
50///     [D, D, 'D', d],
51///     [E, E, 'E', e]
52/// );
53/// union_struct!(
54///     (pub(crate)),
55///     Union6,
56///     Union6<T, T, T, T, T, T>,
57///     [A, A, 'A', a],
58///     [B, B, 'B', b],
59///     [C, C, 'C', c],
60///     [D, D, 'D', d],
61///     [E, E, 'E', e],
62///     [F, F, 'F', f]
63/// );
64/// union_struct!(
65///     (pub(crate)),
66///     Union7,
67///     Union7<T, T, T, T, T, T, T>,
68///     [A, A, 'A', a],
69///     [B, B, 'B', b],
70///     [C, C, 'C', c],
71///     [D, D, 'D', d],
72///     [E, E, 'E', e],
73///     [F, F, 'F', f],
74///     [G, G, 'G', g]
75/// );
76/// union_struct!(
77///     (pub(crate)),
78///     Union8,
79///     Union8<T, T, T, T, T, T, T, T>,
80///     [A, A, 'A', a],
81///     [B, B, 'B', b],
82///     [C, C, 'C', c],
83///     [D, D, 'D', d],
84///     [E, E, 'E', e],
85///     [F, F, 'F', f],
86///     [G, G, 'G', g],
87///     [H, H, 'H', h]
88/// );
89///
90/// exhaustive_unions!(
91///     (pub(crate)),
92///     Union3,
93///     LexUnion3s,
94///     ExhaustiveUnion3s,
95///     lex_union3s,
96///     exhaustive_union3s,
97///     3,
98///     [0, X, I, A, xs, xs_done],
99///     [1, Y, J, B, ys, ys_done],
100///     [2, Z, K, C, zs, zs_done]
101/// );
102/// exhaustive_unions!(
103///     (pub(crate)),
104///     Union4,
105///     LexUnion4s,
106///     ExhaustiveUnion4s,
107///     lex_union4s,
108///     exhaustive_union4s,
109///     4,
110///     [0, X, I, A, xs, xs_done],
111///     [1, Y, J, B, ys, ys_done],
112///     [2, Z, K, C, zs, zs_done],
113///     [3, W, L, D, ws, ws_done]
114/// );
115/// exhaustive_unions!(
116///     (pub(crate)),
117///     Union5,
118///     LexUnion5s,
119///     ExhaustiveUnion5s,
120///     lex_union5s,
121///     exhaustive_union5s,
122///     5,
123///     [0, X, I, A, xs, xs_done],
124///     [1, Y, J, B, ys, ys_done],
125///     [2, Z, K, C, zs, zs_done],
126///     [3, W, L, D, ws, ws_done],
127///     [4, V, M, E, vs, vs_done]
128/// );
129/// exhaustive_unions!(
130///     (pub(crate)),
131///     Union6,
132///     LexUnion6s,
133///     ExhaustiveUnion6s,
134///     lex_union6s,
135///     exhaustive_union6s,
136///     6,
137///     [0, X, I, A, xs, xs_done],
138///     [1, Y, J, B, ys, ys_done],
139///     [2, Z, K, C, zs, zs_done],
140///     [3, W, L, D, ws, ws_done],
141///     [4, V, M, E, vs, vs_done],
142///     [5, U, N, F, us, us_done]
143/// );
144/// exhaustive_unions!(
145///     (pub(crate)),
146///     Union7,
147///     LexUnion7s,
148///     ExhaustiveUnion7s,
149///     lex_union7s,
150///     exhaustive_union7s,
151///     7,
152///     [0, X, I, A, xs, xs_done],
153///     [1, Y, J, B, ys, ys_done],
154///     [2, Z, K, C, zs, zs_done],
155///     [3, W, L, D, ws, ws_done],
156///     [4, V, M, E, vs, vs_done],
157///     [5, U, N, F, us, us_done],
158///     [6, T, O, G, ts, ts_done]
159/// );
160/// exhaustive_unions!(
161///     (pub(crate)),
162///     Union8,
163///     LexUnion8s,
164///     ExhaustiveUnion8s,
165///     lex_union8s,
166///     exhaustive_union8s,
167///     8,
168///     [0, X, I, A, xs, xs_done],
169///     [1, Y, J, B, ys, ys_done],
170///     [2, Z, K, C, zs, zs_done],
171///     [3, W, L, D, ws, ws_done],
172///     [4, V, M, E, vs, vs_done],
173///     [5, U, N, F, us, us_done],
174///     [6, T, O, G, ts, ts_done],
175///     [7, S, P, H, ss, ss_done]
176/// );
177/// ```
178#[macro_export]
179macro_rules! exhaustive_unions {
180    (
181        ($($vis:tt)*),
182        $union: ident,
183        $lex_struct: ident,
184        $exhaustive_struct: ident,
185        $lex_fn: ident,
186        $exhaustive_fn: ident,
187        $n: expr,
188        $([$i: expr, $t: ident, $it: ident, $variant: ident, $xs: ident, $xs_done:ident]),*
189    ) => {
190        /// This documentation applies not only to `LexUnion2s`, but also to `LexUnion3s`,
191        /// `LexUnion4s`, and so on. See [`exhaustive_unions`] for more information.
192        ///
193        /// Generates all $n$-unions with elements from $n$ iterators, in lexicographic order.
194        ///
195        /// The order is lexicographic with respect to the order of the element iterators. All of
196        /// the first variant's elements are generated first, followed by the second variant's
197        /// elements, and so on.
198        #[allow(dead_code)]
199        #[derive(Clone, Debug)]
200        $($vis)* struct $lex_struct<$($t, $it: Iterator<Item=$t>),*> {
201            i: u64,
202            $($xs: $it,)*
203        }
204
205        impl<$($t, $it: Iterator<Item=$t>),*> Iterator for $lex_struct<$($t, $it),*> {
206            type Item = $union<$($t),*>;
207
208            fn next(&mut self) -> Option<Self::Item> {
209                loop {
210                    match self.i {
211                        $(
212                            $i => {
213                                let next = self.$xs.next().map($union::$variant);
214                                if next.is_some() {
215                                    return next;
216                                }
217                            },
218                        )*
219                        _ => return None,
220                    }
221                    self.i += 1;
222                }
223            }
224        }
225
226        /// This documentation applies not only to `lex_union2s`, but also to `lex_union3s`,
227        /// `lex_union4s`, and so on. See [`exhaustive_unions`] for more information.
228        ///
229        /// Generates all $n$-unions with elements from $n$ iterators, in lexicographic order.
230        ///
231        /// The order is lexicographic with respect to the order of the element iterators. All of
232        /// the first variant's elements are generated first, followed by the second variant's
233        /// elements, and so on. This means that all of the iterators, except possibly the last one,
234        /// must be finite. For functions that support multiple infinite element iterators, try
235        /// `exhaustive_union[n]s`.
236        ///
237        /// If the last iterator is finite, the output length is the sum of the lengths of all the
238        /// input iterators. If the last iterator is infinite, the output is also infinite.
239        ///
240        /// If all of the input iterators are empty, the output is also empty.
241        ///
242        /// # Examples
243        /// See [here](self#lex_union2s).
244        #[allow(dead_code)]
245        #[inline]
246        $($vis)* const fn $lex_fn<$($t, $it: Iterator<Item=$t>),*>($($xs: $it),*) ->
247                $lex_struct<$($t, $it),*> {
248            $lex_struct {
249                i: 0,
250                $($xs,)*
251            }
252        }
253
254        /// This documentation applies not only to `ExhaustiveUnion2s`, but also to
255        /// `ExhaustiveUnion3s`, `ExhaustiveUnion4s`, and so on. See [`exhaustive_unions`] for more
256        /// information.
257        ///
258        /// Generates all $n$-unions with elements from $n$ iterators.
259        #[allow(dead_code)]
260        #[derive(Clone, Debug)]
261        $($vis)* struct $exhaustive_struct<$($t, $it: Iterator<Item=$t>),*> {
262            done: bool,
263            i: u64,
264            $(
265                $xs: $it,
266                $xs_done: bool,
267            )*
268        }
269
270        impl<$($t, $it: Iterator<Item=$t>),*> Iterator for $exhaustive_struct<$($t, $it),*> {
271            type Item = $union<$($t),*>;
272
273            fn next(&mut self) -> Option<Self::Item> {
274                if self.done {
275                    None
276                } else {
277                    let original_i = self.i;
278                    loop {
279                        let mut next = None;
280                        match self.i {
281                            $(
282                                $i => if !self.$xs_done {
283                                    next = self.$xs.next().map($union::$variant);
284                                    self.$xs_done = next.is_none();
285                                },
286                            )*
287                            _ => unreachable!(),
288                        }
289                        self.i += 1;
290                        if self.i == $n {
291                            self.i = 0;
292                        }
293                        if next.is_some() {
294                            return next;
295                        }
296                        if self.i == original_i {
297                            self.done = true;
298                            return None;
299                        }
300                    }
301                }
302            }
303        }
304
305        /// This documentation applies not only to `exhaustive_union2s`, but also to
306        /// `exhaustive_union3s`, `exhaustive_union4s`, and so on. See [`exhaustive_unions`] for
307        /// more information.
308        ///
309        /// Generates all $n$-unions with elements from $n$ iterators.
310        ///
311        /// The input iterators are advanced in a round-robin fashion. First an element from the
312        /// first variant's iterator is selected, followed by an element from the second variant's
313        /// iterator, and so on until an element has been selected from each iterator. Then another
314        /// element from the first iterator is selected, etc. Iterators that have been exhausted are
315        /// skipped. [`exhaustive_union2s`] behaves just like
316        /// [`Itertools::interleave`]([`itertools::Itertools::interleave`]).
317        ///
318        /// If all input iterators are finite, the output length is the sum of the lengths of the
319        /// iterators. If any iterator is infinite, the output is also infinite.
320        ///
321        /// If all of the input iterators are empty, the output is also empty.
322        ///
323        /// # Examples
324        /// See [here](self#exhaustive_union2s).
325        #[allow(dead_code)]
326        #[inline]
327        $($vis)* const fn $exhaustive_fn<$($t, $it: Iterator<Item=$t>),*>($($xs: $it),*) ->
328                $exhaustive_struct<$($t, $it),*> {
329            $exhaustive_struct {
330                done: false,
331                i: 0,
332                $(
333                    $xs,
334                    $xs_done: false,
335                )*
336            }
337        }
338    }
339}
340
341exhaustive_unions!(
342    (pub),
343    Union2,
344    LexUnion2s,
345    ExhaustiveUnion2s,
346    lex_union2s,
347    exhaustive_union2s,
348    2,
349    [0, X, I, A, xs, xs_done],
350    [1, Y, J, B, ys, ys_done]
351);