Skip to main content

either_of/
lib.rs

1#![no_std]
2#![forbid(unsafe_code)]
3
4//! Utilities for working with enumerated types that contain one of `2..n` other types.
5
6use core::{
7    cmp::Ordering,
8    error::Error,
9    fmt::Display,
10    future::Future,
11    iter::{Product, Sum},
12    pin::Pin,
13    task::{Context, Poll},
14};
15use paste::paste;
16use pin_project_lite::pin_project;
17
18macro_rules! tuples {
19    ($name:ident + $fut_name:ident + $fut_proj:ident {
20        $($ty:ident => ($($rest_variant:ident),*) + <$($mapped_ty:ident),+>),+$(,)?
21    }) => {
22        tuples!($name + $fut_name + $fut_proj {
23            $($ty($ty) => ($($rest_variant),*) + <$($mapped_ty),+>),+
24        });
25    };
26    ($name:ident + $fut_name:ident + $fut_proj:ident {
27        $($variant:ident($ty:ident) => ($($rest_variant:ident),*) + <$($mapped_ty:ident),+>),+$(,)?
28    }) => {
29        #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
30        pub enum $name<$($ty),+> {
31            $($variant ($ty),)+
32        }
33
34        impl<$($ty),+> $name<$($ty),+> {
35            paste! {
36                #[allow(clippy::too_many_arguments)]
37                pub fn map<$([<F $ty>]),+, $([<$ty 1>]),+>(self, $([<$variant:lower>]: [<F $ty>]),+) -> $name<$([<$ty 1>]),+>
38                where
39                    $([<F $ty>]: FnOnce($ty) -> [<$ty 1>],)+
40                {
41                    match self {
42                        $($name::$variant(inner) => $name::$variant([<$variant:lower>](inner)),)+
43                    }
44                }
45
46                $(
47                    pub fn [<map_ $variant:lower>]<Fun, [<$ty 1>]>(self, f: Fun) -> $name<$($mapped_ty),+>
48                    where
49                        Fun: FnOnce($ty) -> [<$ty 1>],
50                    {
51                        match self {
52                            $name::$variant(inner) => $name::$variant(f(inner)),
53                            $($name::$rest_variant(inner) => $name::$rest_variant(inner),)*
54                        }
55                    }
56
57                    pub fn [<inspect_ $variant:lower>]<Fun, [<$ty 1>]>(self, f: Fun) -> Self
58                    where
59                        Fun: FnOnce(&$ty),
60                    {
61                        if let $name::$variant(inner) = &self {
62                            f(inner);
63                        }
64                        self
65                    }
66
67                    pub fn [<is_ $variant:lower>](&self) -> bool {
68                        matches!(self, $name::$variant(_))
69                    }
70
71                    pub fn [<as_ $variant:lower>](&self) -> Option<&$ty> {
72                        match self {
73                            $name::$variant(inner) => Some(inner),
74                            _ => None,
75                        }
76                    }
77
78                    pub fn [<as_ $variant:lower _mut>](&mut self) -> Option<&mut $ty> {
79                        match self {
80                            $name::$variant(inner) => Some(inner),
81                            _ => None,
82                        }
83                    }
84
85                    pub fn [<unwrap_ $variant:lower>](self) -> $ty {
86                        match self {
87                            $name::$variant(inner) => inner,
88                            _ => panic!(concat!(
89                                "called `unwrap_", stringify!([<$variant:lower>]), "()` on a non-`", stringify!($variant), "` variant of `", stringify!($name), "`"
90                            )),
91                        }
92                    }
93
94                    pub fn [<into_ $variant:lower>](self) -> Result<$ty, Self> {
95                        match self {
96                            $name::$variant(inner) => Ok(inner),
97                            _ => Err(self),
98                        }
99                    }
100                )+
101            }
102        }
103
104        impl<$($ty),+> Display for $name<$($ty),+>
105        where
106            $($ty: Display,)+
107        {
108            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
109                match self {
110                    $($name::$variant(this) => this.fmt(f),)+
111                }
112            }
113        }
114
115        impl<$($ty),+> Error for $name<$($ty),+>
116        where
117            $($ty: Error,)+
118        {
119            fn source(&self) -> Option<&(dyn Error + 'static)> {
120                match self {
121                    $($name::$variant(this) => this.source(),)+
122                }
123            }
124        }
125
126        impl<Item, $($ty),+> Iterator for $name<$($ty),+>
127        where
128            $($ty: Iterator<Item = Item>,)+
129        {
130            type Item = Item;
131
132            fn next(&mut self) -> Option<Self::Item> {
133                match self {
134                    $($name::$variant(i) => i.next(),)+
135                }
136            }
137
138            fn size_hint(&self) -> (usize, Option<usize>) {
139                match self {
140                    $($name::$variant(i) => i.size_hint(),)+
141                }
142            }
143
144            fn count(self) -> usize
145            where
146                Self: Sized,
147            {
148                match self {
149                    $($name::$variant(i) => i.count(),)+
150                }
151            }
152
153            fn last(self) -> Option<Self::Item>
154            where
155                Self: Sized,
156            {
157                match self {
158                    $($name::$variant(i) => i.last(),)+
159                }
160            }
161
162            fn nth(&mut self, n: usize) -> Option<Self::Item> {
163                match self {
164                    $($name::$variant(i) => i.nth(n),)+
165                }
166            }
167
168            fn for_each<Fun>(self, f: Fun)
169            where
170                Self: Sized,
171                Fun: FnMut(Self::Item),
172            {
173                match self {
174                    $($name::$variant(i) => i.for_each(f),)+
175                }
176            }
177
178            fn collect<Col: FromIterator<Self::Item>>(self) -> Col
179            where
180                Self: Sized,
181            {
182                match self {
183                    $($name::$variant(i) => i.collect(),)+
184                }
185            }
186
187            fn partition<Col, Fun>(self, f: Fun) -> (Col, Col)
188            where
189                Self: Sized,
190                Col: Default + Extend<Self::Item>,
191                Fun: FnMut(&Self::Item) -> bool,
192            {
193                match self {
194                    $($name::$variant(i) => i.partition(f),)+
195                }
196            }
197
198            fn fold<Acc, Fun>(self, init: Acc, f: Fun) -> Acc
199            where
200                Self: Sized,
201                Fun: FnMut(Acc, Self::Item) -> Acc,
202            {
203                match self {
204                    $($name::$variant(i) => i.fold(init, f),)+
205                }
206            }
207
208            fn reduce<Fun>(self, f: Fun) -> Option<Self::Item>
209            where
210                Self: Sized,
211                Fun: FnMut(Self::Item, Self::Item) -> Self::Item,
212            {
213                match self {
214                    $($name::$variant(i) => i.reduce(f),)+
215                }
216            }
217
218            fn all<Fun>(&mut self, f: Fun) -> bool
219            where
220                Self: Sized,
221                Fun: FnMut(Self::Item) -> bool,
222            {
223                match self {
224                    $($name::$variant(i) => i.all(f),)+
225                }
226            }
227
228            fn any<Fun>(&mut self, f: Fun) -> bool
229            where
230                Self: Sized,
231                Fun: FnMut(Self::Item) -> bool,
232            {
233                match self {
234                    $($name::$variant(i) => i.any(f),)+
235                }
236            }
237
238            fn find<Pre>(&mut self, predicate: Pre) -> Option<Self::Item>
239            where
240                Self: Sized,
241                Pre: FnMut(&Self::Item) -> bool,
242            {
243                match self {
244                    $($name::$variant(i) => i.find(predicate),)+
245                }
246            }
247
248            fn find_map<Out, Fun>(&mut self, f: Fun) -> Option<Out>
249            where
250                Self: Sized,
251                Fun: FnMut(Self::Item) -> Option<Out>,
252            {
253                match self {
254                    $($name::$variant(i) => i.find_map(f),)+
255                }
256            }
257
258            fn position<Pre>(&mut self, predicate: Pre) -> Option<usize>
259            where
260                Self: Sized,
261                Pre: FnMut(Self::Item) -> bool,
262            {
263                match self {
264                    $($name::$variant(i) => i.position(predicate),)+
265                }
266            }
267
268            fn max(self) -> Option<Self::Item>
269            where
270                Self: Sized,
271                Self::Item: Ord,
272            {
273                match self {
274                    $($name::$variant(i) => i.max(),)+
275                }
276            }
277
278            fn min(self) -> Option<Self::Item>
279            where
280                Self: Sized,
281                Self::Item: Ord,
282            {
283                match self {
284                    $($name::$variant(i) => i.min(),)+
285                }
286            }
287
288            fn max_by_key<Key: Ord, Fun>(self, f: Fun) -> Option<Self::Item>
289            where
290                Self: Sized,
291                Fun: FnMut(&Self::Item) -> Key,
292            {
293                match self {
294                    $($name::$variant(i) => i.max_by_key(f),)+
295                }
296            }
297
298            fn max_by<Cmp>(self, compare: Cmp) -> Option<Self::Item>
299            where
300                Self: Sized,
301                Cmp: FnMut(&Self::Item, &Self::Item) -> Ordering,
302            {
303                match self {
304                    $($name::$variant(i) => i.max_by(compare),)+
305                }
306            }
307
308            fn min_by_key<Key: Ord, Fun>(self, f: Fun) -> Option<Self::Item>
309            where
310                Self: Sized,
311                Fun: FnMut(&Self::Item) -> Key,
312            {
313                match self {
314                    $($name::$variant(i) => i.min_by_key(f),)+
315                }
316            }
317
318            fn min_by<Cmp>(self, compare: Cmp) -> Option<Self::Item>
319            where
320                Self: Sized,
321                Cmp: FnMut(&Self::Item, &Self::Item) -> Ordering,
322            {
323                match self {
324                    $($name::$variant(i) => i.min_by(compare),)+
325                }
326            }
327
328            fn sum<Out>(self) -> Out
329            where
330                Self: Sized,
331                Out: Sum<Self::Item>,
332            {
333                match self {
334                    $($name::$variant(i) => i.sum(),)+
335                }
336            }
337
338            fn product<Out>(self) -> Out
339            where
340                Self: Sized,
341                Out: Product<Self::Item>,
342            {
343                match self {
344                    $($name::$variant(i) => i.product(),)+
345                }
346            }
347
348            fn cmp<Other>(self, other: Other) -> Ordering
349            where
350                Other: IntoIterator<Item = Self::Item>,
351                Self::Item: Ord,
352                Self: Sized,
353            {
354                match self {
355                    $($name::$variant(i) => i.cmp(other),)+
356                }
357            }
358
359            fn partial_cmp<Other>(self, other: Other) -> Option<Ordering>
360            where
361                Other: IntoIterator,
362                Self::Item: PartialOrd<Other::Item>,
363                Self: Sized,
364            {
365                match self {
366                    $($name::$variant(i) => i.partial_cmp(other),)+
367                }
368            }
369
370            // TODO: uncomment once MSRV is >= 1.82.0
371            // fn is_sorted(self) -> bool
372            // where
373            //     Self: Sized,
374            //     Self::Item: PartialOrd,
375            // {
376            //     match self {
377            //         $($name::$variant(i) => i.is_sorted(),)+
378            //     }
379            // }
380            //
381            // fn is_sorted_by<Cmp>(self, compare: Cmp) -> bool
382            // where
383            //     Self: Sized,
384            //     Cmp: FnMut(&Self::Item, &Self::Item) -> bool,
385            // {
386            //     match self {
387            //         $($name::$variant(i) => i.is_sorted_by(compare),)+
388            //     }
389            // }
390            //
391            // fn is_sorted_by_key<Fun, Key>(self, f: Fun) -> bool
392            // where
393            //     Self: Sized,
394            //     Fun: FnMut(Self::Item) -> Key,
395            //     Key: PartialOrd,
396            // {
397            //     match self {
398            //         $($name::$variant(i) => i.is_sorted_by_key(f),)+
399            //     }
400            // }
401        }
402
403        impl<Item, $($ty),+> ExactSizeIterator for $name<$($ty),+>
404        where
405            $($ty: ExactSizeIterator<Item = Item>,)+
406        {
407            fn len(&self) -> usize {
408                match self {
409                    $($name::$variant(i) => i.len(),)+
410                }
411            }
412        }
413
414        impl<Item, $($ty),+> DoubleEndedIterator for $name<$($ty),+>
415        where
416            $($ty: DoubleEndedIterator<Item = Item>,)+
417        {
418            fn next_back(&mut self) -> Option<Self::Item> {
419                match self {
420                    $($name::$variant(i) => i.next_back(),)+
421                }
422            }
423
424            fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
425                match self {
426                    $($name::$variant(i) => i.nth_back(n),)+
427                }
428            }
429
430            fn rfind<Pre>(&mut self, predicate: Pre) -> Option<Self::Item>
431            where
432                Pre: FnMut(&Self::Item) -> bool,
433            {
434                match self {
435                    $($name::$variant(i) => i.rfind(predicate),)+
436                }
437            }
438        }
439
440        pin_project! {
441            #[project = $fut_proj]
442            pub enum $fut_name<$($ty),+> {
443                $($variant { #[pin] inner: $ty },)+
444            }
445        }
446
447        impl<$($ty),+> Future for $fut_name<$($ty),+>
448        where
449            $($ty: Future,)+
450        {
451            type Output = $name<$($ty::Output),+>;
452
453            fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
454                let this = self.project();
455                match this {
456                    $($fut_proj::$variant { inner } => match inner.poll(cx) {
457                        Poll::Pending => Poll::Pending,
458                        Poll::Ready(inner) => Poll::Ready($name::$variant(inner)),
459                    },)+
460                }
461            }
462        }
463    }
464}
465
466tuples!(Either + EitherFuture + EitherFutureProj {
467    Left(A) => (Right) + <A1, B>,
468    Right(B) => (Left) + <A, B1>,
469});
470
471impl<A, B> Either<A, B> {
472    pub fn swap(self) -> Either<B, A> {
473        match self {
474            Either::Left(a) => Either::Right(a),
475            Either::Right(b) => Either::Left(b),
476        }
477    }
478}
479
480impl<A, B> From<Result<A, B>> for Either<A, B> {
481    fn from(value: Result<A, B>) -> Self {
482        match value {
483            Ok(left) => Either::Left(left),
484            Err(right) => Either::Right(right),
485        }
486    }
487}
488
489pub trait EitherOr {
490    type Left;
491    type Right;
492    fn either_or<FA, A, FB, B>(self, a: FA, b: FB) -> Either<A, B>
493    where
494        FA: FnOnce(Self::Left) -> A,
495        FB: FnOnce(Self::Right) -> B;
496}
497
498impl EitherOr for bool {
499    type Left = ();
500    type Right = ();
501
502    fn either_or<FA, A, FB, B>(self, a: FA, b: FB) -> Either<A, B>
503    where
504        FA: FnOnce(Self::Left) -> A,
505        FB: FnOnce(Self::Right) -> B,
506    {
507        if self {
508            Either::Left(a(()))
509        } else {
510            Either::Right(b(()))
511        }
512    }
513}
514
515impl<T> EitherOr for Option<T> {
516    type Left = T;
517    type Right = ();
518
519    fn either_or<FA, A, FB, B>(self, a: FA, b: FB) -> Either<A, B>
520    where
521        FA: FnOnce(Self::Left) -> A,
522        FB: FnOnce(Self::Right) -> B,
523    {
524        match self {
525            Some(t) => Either::Left(a(t)),
526            None => Either::Right(b(())),
527        }
528    }
529}
530
531impl<T, E> EitherOr for Result<T, E> {
532    type Left = T;
533    type Right = E;
534
535    fn either_or<FA, A, FB, B>(self, a: FA, b: FB) -> Either<A, B>
536    where
537        FA: FnOnce(Self::Left) -> A,
538        FB: FnOnce(Self::Right) -> B,
539    {
540        match self {
541            Ok(t) => Either::Left(a(t)),
542            Err(err) => Either::Right(b(err)),
543        }
544    }
545}
546
547impl<A, B> EitherOr for Either<A, B> {
548    type Left = A;
549    type Right = B;
550
551    #[inline]
552    fn either_or<FA, A1, FB, B1>(self, a: FA, b: FB) -> Either<A1, B1>
553    where
554        FA: FnOnce(<Self as EitherOr>::Left) -> A1,
555        FB: FnOnce(<Self as EitherOr>::Right) -> B1,
556    {
557        self.map(a, b)
558    }
559}
560
561tuples!(EitherOf3 + EitherOf3Future + EitherOf3FutureProj {
562    A => (B, C) + <A1, B, C>,
563    B => (A, C) + <A, B1, C>,
564    C => (A, B) + <A, B, C1>,
565});
566tuples!(EitherOf4 + EitherOf4Future + EitherOf4FutureProj {
567    A => (B, C, D) + <A1, B, C, D>,
568    B => (A, C, D) + <A, B1, C, D>,
569    C => (A, B, D) + <A, B, C1, D>,
570    D => (A, B, C) + <A, B, C, D1>,
571});
572tuples!(EitherOf5 + EitherOf5Future + EitherOf5FutureProj {
573    A => (B, C, D, E) + <A1, B, C, D, E>,
574    B => (A, C, D, E) + <A, B1, C, D, E>,
575    C => (A, B, D, E) + <A, B, C1, D, E>,
576    D => (A, B, C, E) + <A, B, C, D1, E>,
577    E => (A, B, C, D) + <A, B, C, D, E1>,
578});
579tuples!(EitherOf6 + EitherOf6Future + EitherOf6FutureProj {
580    A => (B, C, D, E, F) + <A1, B, C, D, E, F>,
581    B => (A, C, D, E, F) + <A, B1, C, D, E, F>,
582    C => (A, B, D, E, F) + <A, B, C1, D, E, F>,
583    D => (A, B, C, E, F) + <A, B, C, D1, E, F>,
584    E => (A, B, C, D, F) + <A, B, C, D, E1, F>,
585    F => (A, B, C, D, E) + <A, B, C, D, E, F1>,
586});
587tuples!(EitherOf7 + EitherOf7Future + EitherOf7FutureProj {
588    A => (B, C, D, E, F, G) + <A1, B, C, D, E, F, G>,
589    B => (A, C, D, E, F, G) + <A, B1, C, D, E, F, G>,
590    C => (A, B, D, E, F, G) + <A, B, C1, D, E, F, G>,
591    D => (A, B, C, E, F, G) + <A, B, C, D1, E, F, G>,
592    E => (A, B, C, D, F, G) + <A, B, C, D, E1, F, G>,
593    F => (A, B, C, D, E, G) + <A, B, C, D, E, F1, G>,
594    G => (A, B, C, D, E, F) + <A, B, C, D, E, F, G1>,
595});
596tuples!(EitherOf8 + EitherOf8Future + EitherOf8FutureProj {
597    A => (B, C, D, E, F, G, H) + <A1, B, C, D, E, F, G, H>,
598    B => (A, C, D, E, F, G, H) + <A, B1, C, D, E, F, G, H>,
599    C => (A, B, D, E, F, G, H) + <A, B, C1, D, E, F, G, H>,
600    D => (A, B, C, E, F, G, H) + <A, B, C, D1, E, F, G, H>,
601    E => (A, B, C, D, F, G, H) + <A, B, C, D, E1, F, G, H>,
602    F => (A, B, C, D, E, G, H) + <A, B, C, D, E, F1, G, H>,
603    G => (A, B, C, D, E, F, H) + <A, B, C, D, E, F, G1, H>,
604    H => (A, B, C, D, E, F, G) + <A, B, C, D, E, F, G, H1>,
605});
606tuples!(EitherOf9 + EitherOf9Future + EitherOf9FutureProj {
607    A => (B, C, D, E, F, G, H, I) + <A1, B, C, D, E, F, G, H, I>,
608    B => (A, C, D, E, F, G, H, I) + <A, B1, C, D, E, F, G, H, I>,
609    C => (A, B, D, E, F, G, H, I) + <A, B, C1, D, E, F, G, H, I>,
610    D => (A, B, C, E, F, G, H, I) + <A, B, C, D1, E, F, G, H, I>,
611    E => (A, B, C, D, F, G, H, I) + <A, B, C, D, E1, F, G, H, I>,
612    F => (A, B, C, D, E, G, H, I) + <A, B, C, D, E, F1, G, H, I>,
613    G => (A, B, C, D, E, F, H, I) + <A, B, C, D, E, F, G1, H, I>,
614    H => (A, B, C, D, E, F, G, I) + <A, B, C, D, E, F, G, H1, I>,
615    I => (A, B, C, D, E, F, G, H) + <A, B, C, D, E, F, G, H, I1>,
616});
617tuples!(EitherOf10 + EitherOf10Future + EitherOf10FutureProj {
618    A => (B, C, D, E, F, G, H, I, J) + <A1, B, C, D, E, F, G, H, I, J>,
619    B => (A, C, D, E, F, G, H, I, J) + <A, B1, C, D, E, F, G, H, I, J>,
620    C => (A, B, D, E, F, G, H, I, J) + <A, B, C1, D, E, F, G, H, I, J>,
621    D => (A, B, C, E, F, G, H, I, J) + <A, B, C, D1, E, F, G, H, I, J>,
622    E => (A, B, C, D, F, G, H, I, J) + <A, B, C, D, E1, F, G, H, I, J>,
623    F => (A, B, C, D, E, G, H, I, J) + <A, B, C, D, E, F1, G, H, I, J>,
624    G => (A, B, C, D, E, F, H, I, J) + <A, B, C, D, E, F, G1, H, I, J>,
625    H => (A, B, C, D, E, F, G, I, J) + <A, B, C, D, E, F, G, H1, I, J>,
626    I => (A, B, C, D, E, F, G, H, J) + <A, B, C, D, E, F, G, H, I1, J>,
627    J => (A, B, C, D, E, F, G, H, I) + <A, B, C, D, E, F, G, H, I, J1>,
628});
629tuples!(EitherOf11 + EitherOf11Future + EitherOf11FutureProj {
630    A => (B, C, D, E, F, G, H, I, J, K) + <A1, B, C, D, E, F, G, H, I, J, K>,
631    B => (A, C, D, E, F, G, H, I, J, K) + <A, B1, C, D, E, F, G, H, I, J, K>,
632    C => (A, B, D, E, F, G, H, I, J, K) + <A, B, C1, D, E, F, G, H, I, J, K>,
633    D => (A, B, C, E, F, G, H, I, J, K) + <A, B, C, D1, E, F, G, H, I, J, K>,
634    E => (A, B, C, D, F, G, H, I, J, K) + <A, B, C, D, E1, F, G, H, I, J, K>,
635    F => (A, B, C, D, E, G, H, I, J, K) + <A, B, C, D, E, F1, G, H, I, J, K>,
636    G => (A, B, C, D, E, F, H, I, J, K) + <A, B, C, D, E, F, G1, H, I, J, K>,
637    H => (A, B, C, D, E, F, G, I, J, K) + <A, B, C, D, E, F, G, H1, I, J, K>,
638    I => (A, B, C, D, E, F, G, H, J, K) + <A, B, C, D, E, F, G, H, I1, J, K>,
639    J => (A, B, C, D, E, F, G, H, I, K) + <A, B, C, D, E, F, G, H, I, J1, K>,
640    K => (A, B, C, D, E, F, G, H, I, J) + <A, B, C, D, E, F, G, H, I, J, K1>,
641});
642tuples!(EitherOf12 + EitherOf12Future + EitherOf12FutureProj {
643    A => (B, C, D, E, F, G, H, I, J, K, L) + <A1, B, C, D, E, F, G, H, I, J, K, L>,
644    B => (A, C, D, E, F, G, H, I, J, K, L) + <A, B1, C, D, E, F, G, H, I, J, K, L>,
645    C => (A, B, D, E, F, G, H, I, J, K, L) + <A, B, C1, D, E, F, G, H, I, J, K, L>,
646    D => (A, B, C, E, F, G, H, I, J, K, L) + <A, B, C, D1, E, F, G, H, I, J, K, L>,
647    E => (A, B, C, D, F, G, H, I, J, K, L) + <A, B, C, D, E1, F, G, H, I, J, K, L>,
648    F => (A, B, C, D, E, G, H, I, J, K, L) + <A, B, C, D, E, F1, G, H, I, J, K, L>,
649    G => (A, B, C, D, E, F, H, I, J, K, L) + <A, B, C, D, E, F, G1, H, I, J, K, L>,
650    H => (A, B, C, D, E, F, G, I, J, K, L) + <A, B, C, D, E, F, G, H1, I, J, K, L>,
651    I => (A, B, C, D, E, F, G, H, J, K, L) + <A, B, C, D, E, F, G, H, I1, J, K, L>,
652    J => (A, B, C, D, E, F, G, H, I, K, L) + <A, B, C, D, E, F, G, H, I, J1, K, L>,
653    K => (A, B, C, D, E, F, G, H, I, J, L) + <A, B, C, D, E, F, G, H, I, J, K1, L>,
654    L => (A, B, C, D, E, F, G, H, I, J, K) + <A, B, C, D, E, F, G, H, I, J, K, L1>,
655});
656tuples!(EitherOf13 + EitherOf13Future + EitherOf13FutureProj {
657    A => (B, C, D, E, F, G, H, I, J, K, L, M) + <A1, B, C, D, E, F, G, H, I, J, K, L, M>,
658    B => (A, C, D, E, F, G, H, I, J, K, L, M) + <A, B1, C, D, E, F, G, H, I, J, K, L, M>,
659    C => (A, B, D, E, F, G, H, I, J, K, L, M) + <A, B, C1, D, E, F, G, H, I, J, K, L, M>,
660    D => (A, B, C, E, F, G, H, I, J, K, L, M) + <A, B, C, D1, E, F, G, H, I, J, K, L, M>,
661    E => (A, B, C, D, F, G, H, I, J, K, L, M) + <A, B, C, D, E1, F, G, H, I, J, K, L, M>,
662    F => (A, B, C, D, E, G, H, I, J, K, L, M) + <A, B, C, D, E, F1, G, H, I, J, K, L, M>,
663    G => (A, B, C, D, E, F, H, I, J, K, L, M) + <A, B, C, D, E, F, G1, H, I, J, K, L, M>,
664    H => (A, B, C, D, E, F, G, I, J, K, L, M) + <A, B, C, D, E, F, G, H1, I, J, K, L, M>,
665    I => (A, B, C, D, E, F, G, H, J, K, L, M) + <A, B, C, D, E, F, G, H, I1, J, K, L, M>,
666    J => (A, B, C, D, E, F, G, H, I, K, L, M) + <A, B, C, D, E, F, G, H, I, J1, K, L, M>,
667    K => (A, B, C, D, E, F, G, H, I, J, L, M) + <A, B, C, D, E, F, G, H, I, J, K1, L, M>,
668    L => (A, B, C, D, E, F, G, H, I, J, K, M) + <A, B, C, D, E, F, G, H, I, J, K, L1, M>,
669    M => (A, B, C, D, E, F, G, H, I, J, K, L) + <A, B, C, D, E, F, G, H, I, J, K, L, M1>,
670});
671tuples!(EitherOf14 + EitherOf14Future + EitherOf14FutureProj {
672    A => (B, C, D, E, F, G, H, I, J, K, L, M, N) + <A1, B, C, D, E, F, G, H, I, J, K, L, M, N>,
673    B => (A, C, D, E, F, G, H, I, J, K, L, M, N) + <A, B1, C, D, E, F, G, H, I, J, K, L, M, N>,
674    C => (A, B, D, E, F, G, H, I, J, K, L, M, N) + <A, B, C1, D, E, F, G, H, I, J, K, L, M, N>,
675    D => (A, B, C, E, F, G, H, I, J, K, L, M, N) + <A, B, C, D1, E, F, G, H, I, J, K, L, M, N>,
676    E => (A, B, C, D, F, G, H, I, J, K, L, M, N) + <A, B, C, D, E1, F, G, H, I, J, K, L, M, N>,
677    F => (A, B, C, D, E, G, H, I, J, K, L, M, N) + <A, B, C, D, E, F1, G, H, I, J, K, L, M, N>,
678    G => (A, B, C, D, E, F, H, I, J, K, L, M, N) + <A, B, C, D, E, F, G1, H, I, J, K, L, M, N>,
679    H => (A, B, C, D, E, F, G, I, J, K, L, M, N) + <A, B, C, D, E, F, G, H1, I, J, K, L, M, N>,
680    I => (A, B, C, D, E, F, G, H, J, K, L, M, N) + <A, B, C, D, E, F, G, H, I1, J, K, L, M, N>,
681    J => (A, B, C, D, E, F, G, H, I, K, L, M, N) + <A, B, C, D, E, F, G, H, I, J1, K, L, M, N>,
682    K => (A, B, C, D, E, F, G, H, I, J, L, M, N) + <A, B, C, D, E, F, G, H, I, J, K1, L, M, N>,
683    L => (A, B, C, D, E, F, G, H, I, J, K, M, N) + <A, B, C, D, E, F, G, H, I, J, K, L1, M, N>,
684    M => (A, B, C, D, E, F, G, H, I, J, K, L, N) + <A, B, C, D, E, F, G, H, I, J, K, L, M1, N>,
685    N => (A, B, C, D, E, F, G, H, I, J, K, L, M) + <A, B, C, D, E, F, G, H, I, J, K, L, M, N1>,
686});
687tuples!(EitherOf15 + EitherOf15Future + EitherOf15FutureProj {
688    A => (B, C, D, E, F, G, H, I, J, K, L, M, N, O) + <A1, B, C, D, E, F, G, H, I, J, K, L, M, N, O>,
689    B => (A, C, D, E, F, G, H, I, J, K, L, M, N, O) + <A, B1, C, D, E, F, G, H, I, J, K, L, M, N, O>,
690    C => (A, B, D, E, F, G, H, I, J, K, L, M, N, O) + <A, B, C1, D, E, F, G, H, I, J, K, L, M, N, O>,
691    D => (A, B, C, E, F, G, H, I, J, K, L, M, N, O) + <A, B, C, D1, E, F, G, H, I, J, K, L, M, N, O>,
692    E => (A, B, C, D, F, G, H, I, J, K, L, M, N, O) + <A, B, C, D, E1, F, G, H, I, J, K, L, M, N, O>,
693    F => (A, B, C, D, E, G, H, I, J, K, L, M, N, O) + <A, B, C, D, E, F1, G, H, I, J, K, L, M, N, O>,
694    G => (A, B, C, D, E, F, H, I, J, K, L, M, N, O) + <A, B, C, D, E, F, G1, H, I, J, K, L, M, N, O>,
695    H => (A, B, C, D, E, F, G, I, J, K, L, M, N, O) + <A, B, C, D, E, F, G, H1, I, J, K, L, M, N, O>,
696    I => (A, B, C, D, E, F, G, H, J, K, L, M, N, O) + <A, B, C, D, E, F, G, H, I1, J, K, L, M, N, O>,
697    J => (A, B, C, D, E, F, G, H, I, K, L, M, N, O) + <A, B, C, D, E, F, G, H, I, J1, K, L, M, N, O>,
698    K => (A, B, C, D, E, F, G, H, I, J, L, M, N, O) + <A, B, C, D, E, F, G, H, I, J, K1, L, M, N, O>,
699    L => (A, B, C, D, E, F, G, H, I, J, K, M, N, O) + <A, B, C, D, E, F, G, H, I, J, K, L1, M, N, O>,
700    M => (A, B, C, D, E, F, G, H, I, J, K, L, N, O) + <A, B, C, D, E, F, G, H, I, J, K, L, M1, N, O>,
701    N => (A, B, C, D, E, F, G, H, I, J, K, L, M, O) + <A, B, C, D, E, F, G, H, I, J, K, L, M, N1, O>,
702    O => (A, B, C, D, E, F, G, H, I, J, K, L, M, N) + <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O1>,
703});
704tuples!(EitherOf16 + EitherOf16Future + EitherOf16FutureProj {
705    A => (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) + <A1, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P>,
706    B => (A, C, D, E, F, G, H, I, J, K, L, M, N, O, P) + <A, B1, C, D, E, F, G, H, I, J, K, L, M, N, O, P>,
707    C => (A, B, D, E, F, G, H, I, J, K, L, M, N, O, P) + <A, B, C1, D, E, F, G, H, I, J, K, L, M, N, O, P>,
708    D => (A, B, C, E, F, G, H, I, J, K, L, M, N, O, P) + <A, B, C, D1, E, F, G, H, I, J, K, L, M, N, O, P>,
709    E => (A, B, C, D, F, G, H, I, J, K, L, M, N, O, P) + <A, B, C, D, E1, F, G, H, I, J, K, L, M, N, O, P>,
710    F => (A, B, C, D, E, G, H, I, J, K, L, M, N, O, P) + <A, B, C, D, E, F1, G, H, I, J, K, L, M, N, O, P>,
711    G => (A, B, C, D, E, F, H, I, J, K, L, M, N, O, P) + <A, B, C, D, E, F, G1, H, I, J, K, L, M, N, O, P>,
712    H => (A, B, C, D, E, F, G, I, J, K, L, M, N, O, P) + <A, B, C, D, E, F, G, H1, I, J, K, L, M, N, O, P>,
713    I => (A, B, C, D, E, F, G, H, J, K, L, M, N, O, P) + <A, B, C, D, E, F, G, H, I1, J, K, L, M, N, O, P>,
714    J => (A, B, C, D, E, F, G, H, I, K, L, M, N, O, P) + <A, B, C, D, E, F, G, H, I, J1, K, L, M, N, O, P>,
715    K => (A, B, C, D, E, F, G, H, I, J, L, M, N, O, P) + <A, B, C, D, E, F, G, H, I, J, K1, L, M, N, O, P>,
716    L => (A, B, C, D, E, F, G, H, I, J, K, M, N, O, P) + <A, B, C, D, E, F, G, H, I, J, K, L1, M, N, O, P>,
717    M => (A, B, C, D, E, F, G, H, I, J, K, L, N, O, P) + <A, B, C, D, E, F, G, H, I, J, K, L, M1, N, O, P>,
718    N => (A, B, C, D, E, F, G, H, I, J, K, L, M, O, P) + <A, B, C, D, E, F, G, H, I, J, K, L, M, N1, O, P>,
719    O => (A, B, C, D, E, F, G, H, I, J, K, L, M, N, P) + <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O1, P>,
720    P => (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) + <A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P1>,
721});
722// if you need more eithers feel free to open a PR ;-)
723
724/// Matches over the first expression and returns an either ([`Either`], [`EitherOf3`], ... [`EitherOf8`])
725/// composed of the values returned by the match arms.
726///
727/// The pattern syntax is exactly the same as found in a match arm.
728///
729/// # Examples
730///
731/// ```
732/// # use either_of::*;
733/// let either2 = either!(Some("hello"),
734///     Some(s) => s.len(),
735///     None => 0.0,
736/// );
737/// assert!(matches!(either2, Either::<usize, f64>::Left(5)));
738///
739/// let either3 = either!(Some("admin"),
740///     Some("admin") => "hello admin",
741///     Some(_) => 'x',
742///     _ => 0,
743/// );
744/// assert!(matches!(either3, EitherOf3::<&str, char, i32>::A("hello admin")));
745/// ```
746#[macro_export]
747macro_rules! either {
748    ($match:expr, $left_pattern:pat => $left_expression:expr, $right_pattern:pat => $right_expression:expr$(,)?) => {
749        match $match {
750            $left_pattern => $crate::Either::Left($left_expression),
751            $right_pattern => $crate::Either::Right($right_expression),
752        }
753    };
754    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr$(,)?) => {
755        match $match {
756            $a_pattern => $crate::EitherOf3::A($a_expression),
757            $b_pattern => $crate::EitherOf3::B($b_expression),
758            $c_pattern => $crate::EitherOf3::C($c_expression),
759        }
760    };
761    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr$(,)?) => {
762        match $match {
763            $a_pattern => $crate::EitherOf4::A($a_expression),
764            $b_pattern => $crate::EitherOf4::B($b_expression),
765            $c_pattern => $crate::EitherOf4::C($c_expression),
766            $d_pattern => $crate::EitherOf4::D($d_expression),
767        }
768    };
769    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr$(,)?) => {
770        match $match {
771            $a_pattern => $crate::EitherOf5::A($a_expression),
772            $b_pattern => $crate::EitherOf5::B($b_expression),
773            $c_pattern => $crate::EitherOf5::C($c_expression),
774            $d_pattern => $crate::EitherOf5::D($d_expression),
775            $e_pattern => $crate::EitherOf5::E($e_expression),
776        }
777    };
778    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr, $f_pattern:pat => $f_expression:expr$(,)?) => {
779        match $match {
780            $a_pattern => $crate::EitherOf6::A($a_expression),
781            $b_pattern => $crate::EitherOf6::B($b_expression),
782            $c_pattern => $crate::EitherOf6::C($c_expression),
783            $d_pattern => $crate::EitherOf6::D($d_expression),
784            $e_pattern => $crate::EitherOf6::E($e_expression),
785            $f_pattern => $crate::EitherOf6::F($f_expression),
786        }
787    };
788    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr, $f_pattern:pat => $f_expression:expr, $g_pattern:pat => $g_expression:expr$(,)?) => {
789        match $match {
790            $a_pattern => $crate::EitherOf7::A($a_expression),
791            $b_pattern => $crate::EitherOf7::B($b_expression),
792            $c_pattern => $crate::EitherOf7::C($c_expression),
793            $d_pattern => $crate::EitherOf7::D($d_expression),
794            $e_pattern => $crate::EitherOf7::E($e_expression),
795            $f_pattern => $crate::EitherOf7::F($f_expression),
796            $g_pattern => $crate::EitherOf7::G($g_expression),
797        }
798    };
799    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr, $f_pattern:pat => $f_expression:expr, $g_pattern:pat => $g_expression:expr, $h_pattern:pat => $h_expression:expr$(,)?) => {
800        match $match {
801            $a_pattern => $crate::EitherOf8::A($a_expression),
802            $b_pattern => $crate::EitherOf8::B($b_expression),
803            $c_pattern => $crate::EitherOf8::C($c_expression),
804            $d_pattern => $crate::EitherOf8::D($d_expression),
805            $e_pattern => $crate::EitherOf8::E($e_expression),
806            $f_pattern => $crate::EitherOf8::F($f_expression),
807            $g_pattern => $crate::EitherOf8::G($g_expression),
808            $h_pattern => $crate::EitherOf8::H($h_expression),
809        }
810    };
811    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr, $f_pattern:pat => $f_expression:expr, $g_pattern:pat => $g_expression:expr, $h_pattern:pat => $h_expression:expr, $i_pattern:pat => $i_expression:expr$(,)?) => {
812        match $match {
813            $a_pattern => $crate::EitherOf9::A($a_expression),
814            $b_pattern => $crate::EitherOf9::B($b_expression),
815            $c_pattern => $crate::EitherOf9::C($c_expression),
816            $d_pattern => $crate::EitherOf9::D($d_expression),
817            $e_pattern => $crate::EitherOf9::E($e_expression),
818            $f_pattern => $crate::EitherOf9::F($f_expression),
819            $g_pattern => $crate::EitherOf9::G($g_expression),
820            $h_pattern => $crate::EitherOf9::H($h_expression),
821            $i_pattern => $crate::EitherOf9::I($i_expression),
822        }
823    };
824    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr, $f_pattern:pat => $f_expression:expr, $g_pattern:pat => $g_expression:expr, $h_pattern:pat => $h_expression:expr, $i_pattern:pat => $i_expression:expr, $j_pattern:pat => $j_expression:expr$(,)?) => {
825        match $match {
826            $a_pattern => $crate::EitherOf10::A($a_expression),
827            $b_pattern => $crate::EitherOf10::B($b_expression),
828            $c_pattern => $crate::EitherOf10::C($c_expression),
829            $d_pattern => $crate::EitherOf10::D($d_expression),
830            $e_pattern => $crate::EitherOf10::E($e_expression),
831            $f_pattern => $crate::EitherOf10::F($f_expression),
832            $g_pattern => $crate::EitherOf10::G($g_expression),
833            $h_pattern => $crate::EitherOf10::H($h_expression),
834            $i_pattern => $crate::EitherOf10::I($i_expression),
835            $j_pattern => $crate::EitherOf10::J($j_expression),
836        }
837    };
838    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr, $f_pattern:pat => $f_expression:expr, $g_pattern:pat => $g_expression:expr, $h_pattern:pat => $h_expression:expr, $i_pattern:pat => $i_expression:expr, $j_pattern:pat => $j_expression:expr, $k_pattern:pat => $k_expression:expr$(,)?) => {
839        match $match {
840            $a_pattern => $crate::EitherOf11::A($a_expression),
841            $b_pattern => $crate::EitherOf11::B($b_expression),
842            $c_pattern => $crate::EitherOf11::C($c_expression),
843            $d_pattern => $crate::EitherOf11::D($d_expression),
844            $e_pattern => $crate::EitherOf11::E($e_expression),
845            $f_pattern => $crate::EitherOf11::F($f_expression),
846            $g_pattern => $crate::EitherOf11::G($g_expression),
847            $h_pattern => $crate::EitherOf11::H($h_expression),
848            $i_pattern => $crate::EitherOf11::I($i_expression),
849            $j_pattern => $crate::EitherOf11::J($j_expression),
850            $k_pattern => $crate::EitherOf11::K($k_expression),
851        }
852    };
853    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr, $f_pattern:pat => $f_expression:expr, $g_pattern:pat => $g_expression:expr, $h_pattern:pat => $h_expression:expr, $i_pattern:pat => $i_expression:expr, $j_pattern:pat => $j_expression:expr, $k_pattern:pat => $k_expression:expr, $l_pattern:pat => $l_expression:expr$(,)?) => {
854        match $match {
855            $a_pattern => $crate::EitherOf12::A($a_expression),
856            $b_pattern => $crate::EitherOf12::B($b_expression),
857            $c_pattern => $crate::EitherOf12::C($c_expression),
858            $d_pattern => $crate::EitherOf12::D($d_expression),
859            $e_pattern => $crate::EitherOf12::E($e_expression),
860            $f_pattern => $crate::EitherOf12::F($f_expression),
861            $g_pattern => $crate::EitherOf12::G($g_expression),
862            $h_pattern => $crate::EitherOf12::H($h_expression),
863            $i_pattern => $crate::EitherOf12::I($i_expression),
864            $j_pattern => $crate::EitherOf12::J($j_expression),
865            $k_pattern => $crate::EitherOf12::K($k_expression),
866            $l_pattern => $crate::EitherOf12::L($l_expression),
867        }
868    };
869    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr, $f_pattern:pat => $f_expression:expr, $g_pattern:pat => $g_expression:expr, $h_pattern:pat => $h_expression:expr, $i_pattern:pat => $i_expression:expr, $j_pattern:pat => $j_expression:expr, $k_pattern:pat => $k_expression:expr, $l_pattern:pat => $l_expression:expr, $m_pattern:pat => $m_expression:expr$(,)?) => {
870        match $match {
871            $a_pattern => $crate::EitherOf13::A($a_expression),
872            $b_pattern => $crate::EitherOf13::B($b_expression),
873            $c_pattern => $crate::EitherOf13::C($c_expression),
874            $d_pattern => $crate::EitherOf13::D($d_expression),
875            $e_pattern => $crate::EitherOf13::E($e_expression),
876            $f_pattern => $crate::EitherOf13::F($f_expression),
877            $g_pattern => $crate::EitherOf13::G($g_expression),
878            $h_pattern => $crate::EitherOf13::H($h_expression),
879            $i_pattern => $crate::EitherOf13::I($i_expression),
880            $j_pattern => $crate::EitherOf13::J($j_expression),
881            $k_pattern => $crate::EitherOf13::K($k_expression),
882            $l_pattern => $crate::EitherOf13::L($l_expression),
883            $m_pattern => $crate::EitherOf13::M($m_expression),
884        }
885    };
886    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr, $f_pattern:pat => $f_expression:expr, $g_pattern:pat => $g_expression:expr, $h_pattern:pat => $h_expression:expr, $i_pattern:pat => $i_expression:expr, $j_pattern:pat => $j_expression:expr, $k_pattern:pat => $k_expression:expr, $l_pattern:pat => $l_expression:expr, $m_pattern:pat => $m_expression:expr, $n_pattern:pat => $n_expression:expr$(,)?) => {
887        match $match {
888            $a_pattern => $crate::EitherOf14::A($a_expression),
889            $b_pattern => $crate::EitherOf14::B($b_expression),
890            $c_pattern => $crate::EitherOf14::C($c_expression),
891            $d_pattern => $crate::EitherOf14::D($d_expression),
892            $e_pattern => $crate::EitherOf14::E($e_expression),
893            $f_pattern => $crate::EitherOf14::F($f_expression),
894            $g_pattern => $crate::EitherOf14::G($g_expression),
895            $h_pattern => $crate::EitherOf14::H($h_expression),
896            $i_pattern => $crate::EitherOf14::I($i_expression),
897            $j_pattern => $crate::EitherOf14::J($j_expression),
898            $k_pattern => $crate::EitherOf14::K($k_expression),
899            $l_pattern => $crate::EitherOf14::L($l_expression),
900            $m_pattern => $crate::EitherOf14::M($m_expression),
901            $n_pattern => $crate::EitherOf14::N($n_expression),
902        }
903    };
904    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr, $f_pattern:pat => $f_expression:expr, $g_pattern:pat => $g_expression:expr, $h_pattern:pat => $h_expression:expr, $i_pattern:pat => $i_expression:expr, $j_pattern:pat => $j_expression:expr, $k_pattern:pat => $k_expression:expr, $l_pattern:pat => $l_expression:expr, $m_pattern:pat => $m_expression:expr, $n_pattern:pat => $n_expression:expr, $o_pattern:pat => $o_expression:expr$(,)?) => {
905        match $match {
906            $a_pattern => $crate::EitherOf15::A($a_expression),
907            $b_pattern => $crate::EitherOf15::B($b_expression),
908            $c_pattern => $crate::EitherOf15::C($c_expression),
909            $d_pattern => $crate::EitherOf15::D($d_expression),
910            $e_pattern => $crate::EitherOf15::E($e_expression),
911            $f_pattern => $crate::EitherOf15::F($f_expression),
912            $g_pattern => $crate::EitherOf15::G($g_expression),
913            $h_pattern => $crate::EitherOf15::H($h_expression),
914            $i_pattern => $crate::EitherOf15::I($i_expression),
915            $j_pattern => $crate::EitherOf15::J($j_expression),
916            $k_pattern => $crate::EitherOf15::K($k_expression),
917            $l_pattern => $crate::EitherOf15::L($l_expression),
918            $m_pattern => $crate::EitherOf15::M($m_expression),
919            $n_pattern => $crate::EitherOf15::N($n_expression),
920            $o_pattern => $crate::EitherOf15::O($o_expression),
921        }
922    };
923    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr, $d_pattern:pat => $d_expression:expr, $e_pattern:pat => $e_expression:expr, $f_pattern:pat => $f_expression:expr, $g_pattern:pat => $g_expression:expr, $h_pattern:pat => $h_expression:expr, $i_pattern:pat => $i_expression:expr, $j_pattern:pat => $j_expression:expr, $k_pattern:pat => $k_expression:expr, $l_pattern:pat => $l_expression:expr, $m_pattern:pat => $m_expression:expr, $n_pattern:pat => $n_expression:expr, $o_pattern:pat => $o_expression:expr, $p_pattern:pat => $p_expression:expr$(,)?) => {
924        match $match {
925            $a_pattern => $crate::EitherOf16::A($a_expression),
926            $b_pattern => $crate::EitherOf16::B($b_expression),
927            $c_pattern => $crate::EitherOf16::C($c_expression),
928            $d_pattern => $crate::EitherOf16::D($d_expression),
929            $e_pattern => $crate::EitherOf16::E($e_expression),
930            $f_pattern => $crate::EitherOf16::F($f_expression),
931            $g_pattern => $crate::EitherOf16::G($g_expression),
932            $h_pattern => $crate::EitherOf16::H($h_expression),
933            $i_pattern => $crate::EitherOf16::I($i_expression),
934            $j_pattern => $crate::EitherOf16::J($j_expression),
935            $k_pattern => $crate::EitherOf16::K($k_expression),
936            $l_pattern => $crate::EitherOf16::L($l_expression),
937            $m_pattern => $crate::EitherOf16::M($m_expression),
938            $n_pattern => $crate::EitherOf16::N($n_expression),
939            $o_pattern => $crate::EitherOf16::O($o_expression),
940            $p_pattern => $crate::EitherOf16::P($p_expression),
941        }
942    };
943}
944
945/// Convenience macro for refering to `Either` types by listing their variants.
946///
947/// # Example
948///
949/// ```no_run
950/// use either_of::Either;
951///
952/// let _: either_of::EitherOf3<u8, i8, u32> = <Either!(u8, i8, u32)>::A(0);
953/// ```
954/// A single type parameter equates to its value:
955/// ```no_run
956/// # use either_of::Either;
957/// let a: Either!(i32) = 0;
958/// let _: i32 = a;
959/// ```
960#[macro_export]
961macro_rules! Either { // TODO: add `() => {!}` branch when the "never" type gets stabilized
962    ($A:ty$(,)?) => {
963        $A
964    };
965    ($A:ty, $B:ty$(,)?) => {
966        $crate::Either<$A, $B>
967    };
968    ($A:ty, $B:ty, $C:ty$(,)?) => {
969        $crate::EitherOf3<$A, $B, $C>
970    };
971    ($A:ty, $B:ty, $C:ty, $D:ty$(,)?) => {
972        $crate::EitherOf4<$A, $B, $C, $D>
973    };
974    ($A:ty, $B:ty, $C:ty, $D:ty, $E:ty$(,)?) => {
975        $crate::EitherOf5<$A, $B, $C, $D, $E>
976    };
977    ($A:ty, $B:ty, $C:ty, $D:ty, $E:ty, $F:ty$(,)?) => {
978        $crate::EitherOf6<$A, $B, $C, $D, $E, $F>
979    };
980    ($A:ty, $B:ty, $C:ty, $D:ty, $E:ty, $F:ty, $G:ty$(,)?) => {
981        $crate::EitherOf7<$A, $B, $C, $D, $E, $F, $G>
982    };
983    ($A:ty, $B:ty, $C:ty, $D:ty, $E:ty, $F:ty, $G:ty, $H:ty$(,)?) => {
984        $crate::EitherOf8<$A, $B, $C, $D, $E, $F, $G, $H>
985    };
986    ($A:ty, $B:ty, $C:ty, $D:ty, $E:ty, $F:ty, $G:ty, $H:ty, $I:ty$(,)?) => {
987        $crate::EitherOf9<$A, $B, $C, $D, $E, $F, $G, $H, $I>
988    };
989    ($A:ty, $B:ty, $C:ty, $D:ty, $E:ty, $F:ty, $G:ty, $H:ty, $I:ty, $J:ty$(,)?) => {
990        $crate::EitherOf10<$A, $B, $C, $D, $E, $F, $G, $H, $I, $J>
991    };
992    ($A:ty, $B:ty, $C:ty, $D:ty, $E:ty, $F:ty, $G:ty, $H:ty, $I:ty, $J:ty, $K:ty$(,)?) => {
993        $crate::EitherOf11<$A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K>
994    };
995    ($A:ty, $B:ty, $C:ty, $D:ty, $E:ty, $F:ty, $G:ty, $H:ty, $I:ty, $J:ty, $K:ty, $L:ty$(,)?) => {
996        $crate::EitherOf12<$A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L>
997    };
998    ($A:ty, $B:ty, $C:ty, $D:ty, $E:ty, $F:ty, $G:ty, $H:ty, $I:ty, $J:ty, $K:ty, $L:ty, $M:ty$(,)?) => {
999        $crate::EitherOf13<$A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M>
1000    };
1001    ($A:ty, $B:ty, $C:ty, $D:ty, $E:ty, $F:ty, $G:ty, $H:ty, $I:ty, $J:ty, $K:ty, $L:ty, $M:ty, $N:ty$(,)?) => {
1002        $crate::EitherOf14<$A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M, $N>
1003    };
1004    ($A:ty, $B:ty, $C:ty, $D:ty, $E:ty, $F:ty, $G:ty, $H:ty, $I:ty, $J:ty, $K:ty, $L:ty, $M:ty, $N:ty, $O:ty$(,)?) => {
1005        $crate::EitherOf15<$A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M, $N, $O>
1006    };
1007    ($A:ty, $B:ty, $C:ty, $D:ty, $E:ty, $F:ty, $G:ty, $H:ty, $I:ty, $J:ty, $K:ty, $L:ty, $M:ty, $N:ty, $O:ty, $P:ty$(,)?) => {
1008        $crate::EitherOf16<$A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M, $N, $O, $P>
1009    };
1010}
1011
1012#[cfg(test)]
1013mod tests {
1014    use super::*;
1015
1016    // compile time test
1017    #[test]
1018    #[expect(clippy::type_complexity)]
1019    fn either_macro() {
1020        let a: f64 = 0.0;
1021        let _: Either!(f64) = a;
1022        let a: Either<&str, f64> = either!(12,
1023            12 => "12",
1024            _ => 0.0f64,
1025        );
1026        let _: Either!(&str, f64) = a;
1027        let a: EitherOf3<&str, f64, i32> = either!(12,
1028            12 => "12",
1029            13 => 0.0f64,
1030            _ => 12i32,
1031        );
1032        let _: Either!(&str, f64, i32) = a;
1033        let a: EitherOf4<&str, f64, char, i32> = either!(12,
1034            12 => "12",
1035            13 => 0.0f64,
1036            14 => ' ',
1037            _ => 12i32,
1038        );
1039        let _: Either!(&str, f64, char, i32) = a;
1040        let a: EitherOf5<&str, f64, char, f32, i32> = either!(12,
1041            12 => "12",
1042            13 => 0.0f64,
1043            14 => ' ',
1044            15 => 0.0f32,
1045            _ => 12i32,
1046        );
1047        let _: Either!(&str, f64, char, f32, i32) = a;
1048        let a: EitherOf6<&str, f64, char, f32, u8, i32> = either!(12,
1049            12 => "12",
1050            13 => 0.0f64,
1051            14 => ' ',
1052            15 => 0.0f32,
1053            16 => 24u8,
1054            _ => 12i32,
1055        );
1056        let _: Either!(&str, f64, char, f32, u8, i32) = a;
1057        let a: EitherOf7<&str, f64, char, f32, u8, i8, i32> = either!(12,
1058            12 => "12",
1059            13 => 0.0f64,
1060            14 => ' ',
1061            15 => 0.0f32,
1062            16 => 24u8,
1063            17 => 2i8,
1064            _ => 12i32,
1065        );
1066        let _: Either!(&str, f64, char, f32, u8, i8, i32) = a;
1067        let a: EitherOf8<&str, f64, char, f32, u8, i8, u16, i32> = either!(12,
1068            12 => "12",
1069            13 => 0.0f64,
1070            14 => ' ',
1071            15 => 0.0f32,
1072            16 => 24u8,
1073            17 => 2i8,
1074            18 => 42u16,
1075            _ => 12i32,
1076        );
1077        let _: Either!(&str, f64, char, f32, u8, i8, u16, i32) = a;
1078        let a: EitherOf9<&str, f64, char, f32, u8, i8, u16, i16, i32> = either!(12,
1079            12 => "12",
1080            13 => 0.0f64,
1081            14 => ' ',
1082            15 => 0.0f32,
1083            16 => 24u8,
1084            17 => 2i8,
1085            18 => 42u16,
1086            19 => 64i16,
1087            _ => 12i32,
1088        );
1089        let _: Either!(&str, f64, char, f32, u8, i8, u16, i16, i32) = a;
1090        let a: EitherOf10<&str, f64, char, f32, u8, i8, u16, i16, u32, i32> = either!(12,
1091            12 => "12",
1092            13 => 0.0f64,
1093            14 => ' ',
1094            15 => 0.0f32,
1095            16 => 24u8,
1096            17 => 2i8,
1097            18 => 42u16,
1098            19 => 64i16,
1099            20 => 84u32,
1100            _ => 12i32,
1101        );
1102        let _: Either!(&str, f64, char, f32, u8, i8, u16, i16, u32, i32) = a;
1103        let a: EitherOf11<
1104            &str,
1105            f64,
1106            char,
1107            f32,
1108            u8,
1109            i8,
1110            u16,
1111            i16,
1112            u32,
1113            i32,
1114            u64,
1115        > = either!(12,
1116            12 => "12",
1117            13 => 0.0f64,
1118            14 => ' ',
1119            15 => 0.0f32,
1120            16 => 24u8,
1121            17 => 2i8,
1122            18 => 42u16,
1123            19 => 64i16,
1124            20 => 84u32,
1125            21 => 12i32,
1126            _ => 13u64,
1127        );
1128        let _: Either!(&str, f64, char, f32, u8, i8, u16, i16, u32, i32, u64,) =
1129            a;
1130        let a: EitherOf12<
1131            &str,
1132            f64,
1133            char,
1134            f32,
1135            u8,
1136            i8,
1137            u16,
1138            i16,
1139            u32,
1140            i32,
1141            u64,
1142            i64,
1143        > = either!(12,
1144            12 => "12",
1145            13 => 0.0f64,
1146            14 => ' ',
1147            15 => 0.0f32,
1148            16 => 24u8,
1149            17 => 2i8,
1150            18 => 42u16,
1151            19 => 64i16,
1152            20 => 84u32,
1153            21 => 12i32,
1154            22 => 13u64,
1155            _ => 14i64,
1156        );
1157        let _: Either!(
1158            &str, f64, char, f32, u8, i8, u16, i16, u32, i32, u64, i64
1159        ) = a;
1160        let a: EitherOf13<
1161            &str,
1162            f64,
1163            char,
1164            f32,
1165            u8,
1166            i8,
1167            u16,
1168            i16,
1169            u32,
1170            i32,
1171            u64,
1172            i64,
1173            u128,
1174        > = either!(12,
1175            12 => "12",
1176            13 => 0.0f64,
1177            14 => ' ',
1178            15 => 0.0f32,
1179            16 => 24u8,
1180            17 => 2i8,
1181            18 => 42u16,
1182            19 => 64i16,
1183            20 => 84u32,
1184            21 => 12i32,
1185            22 => 13u64,
1186            23 => 14i64,
1187            _ => 15u128,
1188        );
1189        let _: Either!(
1190            &str, f64, char, f32, u8, i8, u16, i16, u32, i32, u64, i64, u128,
1191        ) = a;
1192        let a: EitherOf14<
1193            &str,
1194            f64,
1195            char,
1196            f32,
1197            u8,
1198            i8,
1199            u16,
1200            i16,
1201            u32,
1202            i32,
1203            u64,
1204            i64,
1205            u128,
1206            i128,
1207        > = either!(12,
1208            12 => "12",
1209            13 => 0.0f64,
1210            14 => ' ',
1211            15 => 0.0f32,
1212            16 => 24u8,
1213            17 => 2i8,
1214            18 => 42u16,
1215            19 => 64i16,
1216            20 => 84u32,
1217            21 => 12i32,
1218            22 => 13u64,
1219            23 => 14i64,
1220            24 => 15u128,
1221            _ => 16i128,
1222        );
1223        let _: Either!(
1224            &str, f64, char, f32, u8, i8, u16, i16, u32, i32, u64, i64, u128,
1225            i128,
1226        ) = a;
1227        let a: EitherOf15<
1228            &str,
1229            f64,
1230            char,
1231            f32,
1232            u8,
1233            i8,
1234            u16,
1235            i16,
1236            u32,
1237            i32,
1238            u64,
1239            i64,
1240            u128,
1241            i128,
1242            [u8; 1],
1243        > = either!(12,
1244            12 => "12",
1245            13 => 0.0f64,
1246            14 => ' ',
1247            15 => 0.0f32,
1248            16 => 24u8,
1249            17 => 2i8,
1250            18 => 42u16,
1251            19 => 64i16,
1252            20 => 84u32,
1253            21 => 12i32,
1254            22 => 13u64,
1255            23 => 14i64,
1256            24 => 15u128,
1257            25 => 16i128,
1258            _ => [1u8],
1259        );
1260        let _: Either!(
1261            &str, f64, char, f32, u8, i8, u16, i16, u32, i32, u64, i64, u128,
1262            i128, [u8; 1],
1263        ) = a;
1264        let a: EitherOf16<
1265            &str,
1266            f64,
1267            char,
1268            f32,
1269            u8,
1270            i8,
1271            u16,
1272            i16,
1273            u32,
1274            i32,
1275            u64,
1276            i64,
1277            u128,
1278            i128,
1279            [u8; 1],
1280            [i8; 1],
1281        > = either!(12,
1282            12 => "12",
1283            13 => 0.0f64,
1284            14 => ' ',
1285            15 => 0.0f32,
1286            16 => 24u8,
1287            17 => 2i8,
1288            18 => 42u16,
1289            19 => 64i16,
1290            20 => 84u32,
1291            21 => 12i32,
1292            22 => 13u64,
1293            23 => 14i64,
1294            24 => 15u128,
1295            25 => 16i128,
1296            26 => [1u8],
1297            _ => [1i8],
1298        );
1299        let _: Either!(
1300            &str, f64, char, f32, u8, i8, u16, i16, u32, i32, u64, i64, u128,
1301            i128, [u8; 1], [i8; 1],
1302        ) = a;
1303    }
1304
1305    #[test]
1306    #[should_panic]
1307    fn unwrap_wrong_either() {
1308        Either::<i32, &str>::Left(0).unwrap_right();
1309    }
1310
1311    #[test]
1312    fn either_or() {
1313        let right = false.either_or(|_| 'a', |_| 12);
1314        assert!(matches!(right, Either::Right(12)));
1315
1316        let left = true.either_or(|_| 'a', |_| 12);
1317        assert!(matches!(left, Either::Left('a')));
1318
1319        let left = Some(12).either_or(|a| a, |_| 'a');
1320        assert!(matches!(left, Either::Left(12)));
1321        let right = None.either_or(|a: i32| a, |_| 'a');
1322        assert!(matches!(right, Either::Right('a')));
1323
1324        let result: Result<_, ()> = Ok(1.2f32);
1325        let left = result.either_or(|a| a * 2f32, |b| b);
1326        assert!(matches!(left, Either::Left(2.4f32)));
1327
1328        let result: Result<i32, _> = Err("12");
1329        let right = result.either_or(|a| a, |b| b.chars().next());
1330        assert!(matches!(right, Either::Right(Some('1'))));
1331
1332        let either = Either::<i32, char>::Left(12);
1333        let left = either.either_or(|a| a, |b| b);
1334        assert!(matches!(left, Either::Left(12)));
1335
1336        let either = Either::<i32, char>::Right('a');
1337        let right = either.either_or(|a| a, |b| b);
1338        assert!(matches!(right, Either::Right('a')));
1339    }
1340}