either_of/
lib.rs

1#![cfg_attr(feature = "no_std", 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    fmt::Display,
9    future::Future,
10    iter::{Product, Sum},
11    pin::Pin,
12    task::{Context, Poll},
13};
14use paste::paste;
15use pin_project_lite::pin_project;
16#[cfg(not(feature = "no_std"))]
17use std::error::Error; // TODO: replace with core::error::Error once MSRV is >= 1.81.0
18
19macro_rules! tuples {
20    ($name:ident + $fut_name:ident + $fut_proj:ident {
21        $($ty:ident => ($($rest_variant:ident),*) + <$($mapped_ty:ident),+>),+$(,)?
22    }) => {
23        tuples!($name + $fut_name + $fut_proj {
24            $($ty($ty) => ($($rest_variant),*) + <$($mapped_ty),+>),+
25        });
26    };
27    ($name:ident + $fut_name:ident + $fut_proj:ident {
28        $($variant:ident($ty:ident) => ($($rest_variant:ident),*) + <$($mapped_ty:ident),+>),+$(,)?
29    }) => {
30        #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
31        pub enum $name<$($ty),+> {
32            $($variant ($ty),)+
33        }
34
35        impl<$($ty),+> $name<$($ty),+> {
36            paste! {
37                #[allow(clippy::too_many_arguments)]
38                pub fn map<$([<F $ty>]),+, $([<$ty 1>]),+>(self, $([<$variant:lower>]: [<F $ty>]),+) -> $name<$([<$ty 1>]),+>
39                where
40                    $([<F $ty>]: FnOnce($ty) -> [<$ty 1>],)+
41                {
42                    match self {
43                        $($name::$variant(inner) => $name::$variant([<$variant:lower>](inner)),)+
44                    }
45                }
46
47                $(
48                    pub fn [<map_ $variant:lower>]<Fun, [<$ty 1>]>(self, f: Fun) -> $name<$($mapped_ty),+>
49                    where
50                        Fun: FnOnce($ty) -> [<$ty 1>],
51                    {
52                        match self {
53                            $name::$variant(inner) => $name::$variant(f(inner)),
54                            $($name::$rest_variant(inner) => $name::$rest_variant(inner),)*
55                        }
56                    }
57
58                    pub fn [<inspect_ $variant:lower>]<Fun, [<$ty 1>]>(self, f: Fun) -> Self
59                    where
60                        Fun: FnOnce(&$ty),
61                    {
62                        if let $name::$variant(inner) = &self {
63                            f(inner);
64                        }
65                        self
66                    }
67
68                    pub fn [<is_ $variant:lower>](&self) -> bool {
69                        matches!(self, $name::$variant(_))
70                    }
71
72                    pub fn [<as_ $variant:lower>](&self) -> Option<&$ty> {
73                        match self {
74                            $name::$variant(inner) => Some(inner),
75                            _ => None,
76                        }
77                    }
78
79                    pub fn [<as_ $variant:lower _mut>](&mut self) -> Option<&mut $ty> {
80                        match self {
81                            $name::$variant(inner) => Some(inner),
82                            _ => None,
83                        }
84                    }
85
86                    pub fn [<unwrap_ $variant:lower>](self) -> $ty {
87                        match self {
88                            $name::$variant(inner) => inner,
89                            _ => panic!(concat!(
90                                "called `unwrap_", stringify!([<$variant:lower>]), "()` on a non-`", stringify!($variant), "` variant of `", stringify!($name), "`"
91                            )),
92                        }
93                    }
94
95                    pub fn [<into_ $variant:lower>](self) -> Result<$ty, Self> {
96                        match self {
97                            $name::$variant(inner) => Ok(inner),
98                            _ => Err(self),
99                        }
100                    }
101                )+
102            }
103        }
104
105        impl<$($ty),+> Display for $name<$($ty),+>
106        where
107            $($ty: Display,)+
108        {
109            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
110                match self {
111                    $($name::$variant(this) => this.fmt(f),)+
112                }
113            }
114        }
115
116        #[cfg(not(feature = "no_std"))]
117        impl<$($ty),+> Error for $name<$($ty),+>
118        where
119            $($ty: Error,)+
120        {
121            fn source(&self) -> Option<&(dyn Error + 'static)> {
122                match self {
123                    $($name::$variant(this) => this.source(),)+
124                }
125            }
126        }
127
128        impl<Item, $($ty),+> Iterator for $name<$($ty),+>
129        where
130            $($ty: Iterator<Item = Item>,)+
131        {
132            type Item = Item;
133
134            fn next(&mut self) -> Option<Self::Item> {
135                match self {
136                    $($name::$variant(i) => i.next(),)+
137                }
138            }
139
140            fn size_hint(&self) -> (usize, Option<usize>) {
141                match self {
142                    $($name::$variant(i) => i.size_hint(),)+
143                }
144            }
145
146            fn count(self) -> usize
147            where
148                Self: Sized,
149            {
150                match self {
151                    $($name::$variant(i) => i.count(),)+
152                }
153            }
154
155            fn last(self) -> Option<Self::Item>
156            where
157                Self: Sized,
158            {
159                match self {
160                    $($name::$variant(i) => i.last(),)+
161                }
162            }
163
164            fn nth(&mut self, n: usize) -> Option<Self::Item> {
165                match self {
166                    $($name::$variant(i) => i.nth(n),)+
167                }
168            }
169
170            fn for_each<Fun>(self, f: Fun)
171            where
172                Self: Sized,
173                Fun: FnMut(Self::Item),
174            {
175                match self {
176                    $($name::$variant(i) => i.for_each(f),)+
177                }
178            }
179
180            fn collect<Col: FromIterator<Self::Item>>(self) -> Col
181            where
182                Self: Sized,
183            {
184                match self {
185                    $($name::$variant(i) => i.collect(),)+
186                }
187            }
188
189            fn partition<Col, Fun>(self, f: Fun) -> (Col, Col)
190            where
191                Self: Sized,
192                Col: Default + Extend<Self::Item>,
193                Fun: FnMut(&Self::Item) -> bool,
194            {
195                match self {
196                    $($name::$variant(i) => i.partition(f),)+
197                }
198            }
199
200            fn fold<Acc, Fun>(self, init: Acc, f: Fun) -> Acc
201            where
202                Self: Sized,
203                Fun: FnMut(Acc, Self::Item) -> Acc,
204            {
205                match self {
206                    $($name::$variant(i) => i.fold(init, f),)+
207                }
208            }
209
210            fn reduce<Fun>(self, f: Fun) -> Option<Self::Item>
211            where
212                Self: Sized,
213                Fun: FnMut(Self::Item, Self::Item) -> Self::Item,
214            {
215                match self {
216                    $($name::$variant(i) => i.reduce(f),)+
217                }
218            }
219
220            fn all<Fun>(&mut self, f: Fun) -> bool
221            where
222                Self: Sized,
223                Fun: FnMut(Self::Item) -> bool,
224            {
225                match self {
226                    $($name::$variant(i) => i.all(f),)+
227                }
228            }
229
230            fn any<Fun>(&mut self, f: Fun) -> bool
231            where
232                Self: Sized,
233                Fun: FnMut(Self::Item) -> bool,
234            {
235                match self {
236                    $($name::$variant(i) => i.any(f),)+
237                }
238            }
239
240            fn find<Pre>(&mut self, predicate: Pre) -> Option<Self::Item>
241            where
242                Self: Sized,
243                Pre: FnMut(&Self::Item) -> bool,
244            {
245                match self {
246                    $($name::$variant(i) => i.find(predicate),)+
247                }
248            }
249
250            fn find_map<Out, Fun>(&mut self, f: Fun) -> Option<Out>
251            where
252                Self: Sized,
253                Fun: FnMut(Self::Item) -> Option<Out>,
254            {
255                match self {
256                    $($name::$variant(i) => i.find_map(f),)+
257                }
258            }
259
260            fn position<Pre>(&mut self, predicate: Pre) -> Option<usize>
261            where
262                Self: Sized,
263                Pre: FnMut(Self::Item) -> bool,
264            {
265                match self {
266                    $($name::$variant(i) => i.position(predicate),)+
267                }
268            }
269
270            fn max(self) -> Option<Self::Item>
271            where
272                Self: Sized,
273                Self::Item: Ord,
274            {
275                match self {
276                    $($name::$variant(i) => i.max(),)+
277                }
278            }
279
280            fn min(self) -> Option<Self::Item>
281            where
282                Self: Sized,
283                Self::Item: Ord,
284            {
285                match self {
286                    $($name::$variant(i) => i.min(),)+
287                }
288            }
289
290            fn max_by_key<Key: Ord, Fun>(self, f: Fun) -> Option<Self::Item>
291            where
292                Self: Sized,
293                Fun: FnMut(&Self::Item) -> Key,
294            {
295                match self {
296                    $($name::$variant(i) => i.max_by_key(f),)+
297                }
298            }
299
300            fn max_by<Cmp>(self, compare: Cmp) -> Option<Self::Item>
301            where
302                Self: Sized,
303                Cmp: FnMut(&Self::Item, &Self::Item) -> Ordering,
304            {
305                match self {
306                    $($name::$variant(i) => i.max_by(compare),)+
307                }
308            }
309
310            fn min_by_key<Key: Ord, Fun>(self, f: Fun) -> Option<Self::Item>
311            where
312                Self: Sized,
313                Fun: FnMut(&Self::Item) -> Key,
314            {
315                match self {
316                    $($name::$variant(i) => i.min_by_key(f),)+
317                }
318            }
319
320            fn min_by<Cmp>(self, compare: Cmp) -> Option<Self::Item>
321            where
322                Self: Sized,
323                Cmp: FnMut(&Self::Item, &Self::Item) -> Ordering,
324            {
325                match self {
326                    $($name::$variant(i) => i.min_by(compare),)+
327                }
328            }
329
330            fn sum<Out>(self) -> Out
331            where
332                Self: Sized,
333                Out: Sum<Self::Item>,
334            {
335                match self {
336                    $($name::$variant(i) => i.sum(),)+
337                }
338            }
339
340            fn product<Out>(self) -> Out
341            where
342                Self: Sized,
343                Out: Product<Self::Item>,
344            {
345                match self {
346                    $($name::$variant(i) => i.product(),)+
347                }
348            }
349
350            fn cmp<Other>(self, other: Other) -> Ordering
351            where
352                Other: IntoIterator<Item = Self::Item>,
353                Self::Item: Ord,
354                Self: Sized,
355            {
356                match self {
357                    $($name::$variant(i) => i.cmp(other),)+
358                }
359            }
360
361            fn partial_cmp<Other>(self, other: Other) -> Option<Ordering>
362            where
363                Other: IntoIterator,
364                Self::Item: PartialOrd<Other::Item>,
365                Self: Sized,
366            {
367                match self {
368                    $($name::$variant(i) => i.partial_cmp(other),)+
369                }
370            }
371
372            // TODO: uncomment once MSRV is >= 1.82.0
373            // fn is_sorted(self) -> bool
374            // where
375            //     Self: Sized,
376            //     Self::Item: PartialOrd,
377            // {
378            //     match self {
379            //         $($name::$variant(i) => i.is_sorted(),)+
380            //     }
381            // }
382            //
383            // fn is_sorted_by<Cmp>(self, compare: Cmp) -> bool
384            // where
385            //     Self: Sized,
386            //     Cmp: FnMut(&Self::Item, &Self::Item) -> bool,
387            // {
388            //     match self {
389            //         $($name::$variant(i) => i.is_sorted_by(compare),)+
390            //     }
391            // }
392            //
393            // fn is_sorted_by_key<Fun, Key>(self, f: Fun) -> bool
394            // where
395            //     Self: Sized,
396            //     Fun: FnMut(Self::Item) -> Key,
397            //     Key: PartialOrd,
398            // {
399            //     match self {
400            //         $($name::$variant(i) => i.is_sorted_by_key(f),)+
401            //     }
402            // }
403        }
404
405        impl<Item, $($ty),+> ExactSizeIterator for $name<$($ty),+>
406        where
407            $($ty: ExactSizeIterator<Item = Item>,)+
408        {
409            fn len(&self) -> usize {
410                match self {
411                    $($name::$variant(i) => i.len(),)+
412                }
413            }
414        }
415
416        impl<Item, $($ty),+> DoubleEndedIterator for $name<$($ty),+>
417        where
418            $($ty: DoubleEndedIterator<Item = Item>,)+
419        {
420            fn next_back(&mut self) -> Option<Self::Item> {
421                match self {
422                    $($name::$variant(i) => i.next_back(),)+
423                }
424            }
425
426            fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
427                match self {
428                    $($name::$variant(i) => i.nth_back(n),)+
429                }
430            }
431
432            fn rfind<Pre>(&mut self, predicate: Pre) -> Option<Self::Item>
433            where
434                Pre: FnMut(&Self::Item) -> bool,
435            {
436                match self {
437                    $($name::$variant(i) => i.rfind(predicate),)+
438                }
439            }
440        }
441
442        pin_project! {
443            #[project = $fut_proj]
444            pub enum $fut_name<$($ty),+> {
445                $($variant { #[pin] inner: $ty },)+
446            }
447        }
448
449        impl<$($ty),+> Future for $fut_name<$($ty),+>
450        where
451            $($ty: Future,)+
452        {
453            type Output = $name<$($ty::Output),+>;
454
455            fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
456                let this = self.project();
457                match this {
458                    $($fut_proj::$variant { inner } => match inner.poll(cx) {
459                        Poll::Pending => Poll::Pending,
460                        Poll::Ready(inner) => Poll::Ready($name::$variant(inner)),
461                    },)+
462                }
463            }
464        }
465    }
466}
467
468tuples!(Either + EitherFuture + EitherFutureProj {
469    Left(A) => (Right) + <A1, B>,
470    Right(B) => (Left) + <A, B1>,
471});
472
473impl<A, B> Either<A, B> {
474    pub fn swap(self) -> Either<B, A> {
475        match self {
476            Either::Left(a) => Either::Right(a),
477            Either::Right(b) => Either::Left(b),
478        }
479    }
480}
481
482impl<A, B> From<Result<A, B>> for Either<A, B> {
483    fn from(value: Result<A, B>) -> Self {
484        match value {
485            Ok(left) => Either::Left(left),
486            Err(right) => Either::Right(right),
487        }
488    }
489}
490
491pub trait EitherOr {
492    type Left;
493    type Right;
494    fn either_or<FA, A, FB, B>(self, a: FA, b: FB) -> Either<A, B>
495    where
496        FA: FnOnce(Self::Left) -> A,
497        FB: FnOnce(Self::Right) -> B;
498}
499
500impl EitherOr for bool {
501    type Left = ();
502    type Right = ();
503
504    fn either_or<FA, A, FB, B>(self, a: FA, b: FB) -> Either<A, B>
505    where
506        FA: FnOnce(Self::Left) -> A,
507        FB: FnOnce(Self::Right) -> B,
508    {
509        if self {
510            Either::Left(a(()))
511        } else {
512            Either::Right(b(()))
513        }
514    }
515}
516
517impl<T> EitherOr for Option<T> {
518    type Left = T;
519    type Right = ();
520
521    fn either_or<FA, A, FB, B>(self, a: FA, b: FB) -> Either<A, B>
522    where
523        FA: FnOnce(Self::Left) -> A,
524        FB: FnOnce(Self::Right) -> B,
525    {
526        match self {
527            Some(t) => Either::Left(a(t)),
528            None => Either::Right(b(())),
529        }
530    }
531}
532
533impl<T, E> EitherOr for Result<T, E> {
534    type Left = T;
535    type Right = E;
536
537    fn either_or<FA, A, FB, B>(self, a: FA, b: FB) -> Either<A, B>
538    where
539        FA: FnOnce(Self::Left) -> A,
540        FB: FnOnce(Self::Right) -> B,
541    {
542        match self {
543            Ok(t) => Either::Left(a(t)),
544            Err(err) => Either::Right(b(err)),
545        }
546    }
547}
548
549impl<A, B> EitherOr for Either<A, B> {
550    type Left = A;
551    type Right = B;
552
553    #[inline]
554    fn either_or<FA, A1, FB, B1>(self, a: FA, b: FB) -> Either<A1, B1>
555    where
556        FA: FnOnce(<Self as EitherOr>::Left) -> A1,
557        FB: FnOnce(<Self as EitherOr>::Right) -> B1,
558    {
559        self.map(a, b)
560    }
561}
562
563#[test]
564fn test_either_or() {
565    let right = false.either_or(|_| 'a', |_| 12);
566    assert!(matches!(right, Either::Right(12)));
567
568    let left = true.either_or(|_| 'a', |_| 12);
569    assert!(matches!(left, Either::Left('a')));
570
571    let left = Some(12).either_or(|a| a, |_| 'a');
572    assert!(matches!(left, Either::Left(12)));
573    let right = None.either_or(|a: i32| a, |_| 'a');
574    assert!(matches!(right, Either::Right('a')));
575
576    let result: Result<_, ()> = Ok(1.2f32);
577    let left = result.either_or(|a| a * 2f32, |b| b);
578    assert!(matches!(left, Either::Left(2.4f32)));
579
580    let result: Result<i32, _> = Err("12");
581    let right = result.either_or(|a| a, |b| b.chars().next());
582    assert!(matches!(right, Either::Right(Some('1'))));
583
584    let either = Either::<i32, char>::Left(12);
585    let left = either.either_or(|a| a, |b| b);
586    assert!(matches!(left, Either::Left(12)));
587
588    let either = Either::<i32, char>::Right('a');
589    let right = either.either_or(|a| a, |b| b);
590    assert!(matches!(right, Either::Right('a')));
591}
592
593tuples!(EitherOf3 + EitherOf3Future + EitherOf3FutureProj {
594    A => (B, C) + <A1, B, C>,
595    B => (A, C) + <A, B1, C>,
596    C => (A, B) + <A, B, C1>,
597});
598tuples!(EitherOf4 + EitherOf4Future + EitherOf4FutureProj {
599    A => (B, C, D) + <A1, B, C, D>,
600    B => (A, C, D) + <A, B1, C, D>,
601    C => (A, B, D) + <A, B, C1, D>,
602    D => (A, B, C) + <A, B, C, D1>,
603});
604tuples!(EitherOf5 + EitherOf5Future + EitherOf5FutureProj {
605    A => (B, C, D, E) + <A1, B, C, D, E>,
606    B => (A, C, D, E) + <A, B1, C, D, E>,
607    C => (A, B, D, E) + <A, B, C1, D, E>,
608    D => (A, B, C, E) + <A, B, C, D1, E>,
609    E => (A, B, C, D) + <A, B, C, D, E1>,
610});
611tuples!(EitherOf6 + EitherOf6Future + EitherOf6FutureProj {
612    A => (B, C, D, E, F) + <A1, B, C, D, E, F>,
613    B => (A, C, D, E, F) + <A, B1, C, D, E, F>,
614    C => (A, B, D, E, F) + <A, B, C1, D, E, F>,
615    D => (A, B, C, E, F) + <A, B, C, D1, E, F>,
616    E => (A, B, C, D, F) + <A, B, C, D, E1, F>,
617    F => (A, B, C, D, E) + <A, B, C, D, E, F1>,
618});
619tuples!(EitherOf7 + EitherOf7Future + EitherOf7FutureProj {
620    A => (B, C, D, E, F, G) + <A1, B, C, D, E, F, G>,
621    B => (A, C, D, E, F, G) + <A, B1, C, D, E, F, G>,
622    C => (A, B, D, E, F, G) + <A, B, C1, D, E, F, G>,
623    D => (A, B, C, E, F, G) + <A, B, C, D1, E, F, G>,
624    E => (A, B, C, D, F, G) + <A, B, C, D, E1, F, G>,
625    F => (A, B, C, D, E, G) + <A, B, C, D, E, F1, G>,
626    G => (A, B, C, D, E, F) + <A, B, C, D, E, F, G1>,
627});
628tuples!(EitherOf8 + EitherOf8Future + EitherOf8FutureProj {
629    A => (B, C, D, E, F, G, H) + <A1, B, C, D, E, F, G, H>,
630    B => (A, C, D, E, F, G, H) + <A, B1, C, D, E, F, G, H>,
631    C => (A, B, D, E, F, G, H) + <A, B, C1, D, E, F, G, H>,
632    D => (A, B, C, E, F, G, H) + <A, B, C, D1, E, F, G, H>,
633    E => (A, B, C, D, F, G, H) + <A, B, C, D, E1, F, G, H>,
634    F => (A, B, C, D, E, G, H) + <A, B, C, D, E, F1, G, H>,
635    G => (A, B, C, D, E, F, H) + <A, B, C, D, E, F, G1, H>,
636    H => (A, B, C, D, E, F, G) + <A, B, C, D, E, F, G, H1>,
637});
638tuples!(EitherOf9 + EitherOf9Future + EitherOf9FutureProj {
639    A => (B, C, D, E, F, G, H, I) + <A1, B, C, D, E, F, G, H, I>,
640    B => (A, C, D, E, F, G, H, I) + <A, B1, C, D, E, F, G, H, I>,
641    C => (A, B, D, E, F, G, H, I) + <A, B, C1, D, E, F, G, H, I>,
642    D => (A, B, C, E, F, G, H, I) + <A, B, C, D1, E, F, G, H, I>,
643    E => (A, B, C, D, F, G, H, I) + <A, B, C, D, E1, F, G, H, I>,
644    F => (A, B, C, D, E, G, H, I) + <A, B, C, D, E, F1, G, H, I>,
645    G => (A, B, C, D, E, F, H, I) + <A, B, C, D, E, F, G1, H, I>,
646    H => (A, B, C, D, E, F, G, I) + <A, B, C, D, E, F, G, H1, I>,
647    I => (A, B, C, D, E, F, G, H) + <A, B, C, D, E, F, G, H, I1>,
648});
649tuples!(EitherOf10 + EitherOf10Future + EitherOf10FutureProj {
650    A => (B, C, D, E, F, G, H, I, J) + <A1, B, C, D, E, F, G, H, I, J>,
651    B => (A, C, D, E, F, G, H, I, J) + <A, B1, C, D, E, F, G, H, I, J>,
652    C => (A, B, D, E, F, G, H, I, J) + <A, B, C1, D, E, F, G, H, I, J>,
653    D => (A, B, C, E, F, G, H, I, J) + <A, B, C, D1, E, F, G, H, I, J>,
654    E => (A, B, C, D, F, G, H, I, J) + <A, B, C, D, E1, F, G, H, I, J>,
655    F => (A, B, C, D, E, G, H, I, J) + <A, B, C, D, E, F1, G, H, I, J>,
656    G => (A, B, C, D, E, F, H, I, J) + <A, B, C, D, E, F, G1, H, I, J>,
657    H => (A, B, C, D, E, F, G, I, J) + <A, B, C, D, E, F, G, H1, I, J>,
658    I => (A, B, C, D, E, F, G, H, J) + <A, B, C, D, E, F, G, H, I1, J>,
659    J => (A, B, C, D, E, F, G, H, I) + <A, B, C, D, E, F, G, H, I, J1>,
660});
661tuples!(EitherOf11 + EitherOf11Future + EitherOf11FutureProj {
662    A => (B, C, D, E, F, G, H, I, J, K) + <A1, B, C, D, E, F, G, H, I, J, K>,
663    B => (A, C, D, E, F, G, H, I, J, K) + <A, B1, C, D, E, F, G, H, I, J, K>,
664    C => (A, B, D, E, F, G, H, I, J, K) + <A, B, C1, D, E, F, G, H, I, J, K>,
665    D => (A, B, C, E, F, G, H, I, J, K) + <A, B, C, D1, E, F, G, H, I, J, K>,
666    E => (A, B, C, D, F, G, H, I, J, K) + <A, B, C, D, E1, F, G, H, I, J, K>,
667    F => (A, B, C, D, E, G, H, I, J, K) + <A, B, C, D, E, F1, G, H, I, J, K>,
668    G => (A, B, C, D, E, F, H, I, J, K) + <A, B, C, D, E, F, G1, H, I, J, K>,
669    H => (A, B, C, D, E, F, G, I, J, K) + <A, B, C, D, E, F, G, H1, I, J, K>,
670    I => (A, B, C, D, E, F, G, H, J, K) + <A, B, C, D, E, F, G, H, I1, J, K>,
671    J => (A, B, C, D, E, F, G, H, I, K) + <A, B, C, D, E, F, G, H, I, J1, K>,
672    K => (A, B, C, D, E, F, G, H, I, J) + <A, B, C, D, E, F, G, H, I, J, K1>,
673});
674tuples!(EitherOf12 + EitherOf12Future + EitherOf12FutureProj {
675    A => (B, C, D, E, F, G, H, I, J, K, L) + <A1, B, C, D, E, F, G, H, I, J, K, L>,
676    B => (A, C, D, E, F, G, H, I, J, K, L) + <A, B1, C, D, E, F, G, H, I, J, K, L>,
677    C => (A, B, D, E, F, G, H, I, J, K, L) + <A, B, C1, D, E, F, G, H, I, J, K, L>,
678    D => (A, B, C, E, F, G, H, I, J, K, L) + <A, B, C, D1, E, F, G, H, I, J, K, L>,
679    E => (A, B, C, D, F, G, H, I, J, K, L) + <A, B, C, D, E1, F, G, H, I, J, K, L>,
680    F => (A, B, C, D, E, G, H, I, J, K, L) + <A, B, C, D, E, F1, G, H, I, J, K, L>,
681    G => (A, B, C, D, E, F, H, I, J, K, L) + <A, B, C, D, E, F, G1, H, I, J, K, L>,
682    H => (A, B, C, D, E, F, G, I, J, K, L) + <A, B, C, D, E, F, G, H1, I, J, K, L>,
683    I => (A, B, C, D, E, F, G, H, J, K, L) + <A, B, C, D, E, F, G, H, I1, J, K, L>,
684    J => (A, B, C, D, E, F, G, H, I, K, L) + <A, B, C, D, E, F, G, H, I, J1, K, L>,
685    K => (A, B, C, D, E, F, G, H, I, J, L) + <A, B, C, D, E, F, G, H, I, J, K1, L>,
686    L => (A, B, C, D, E, F, G, H, I, J, K) + <A, B, C, D, E, F, G, H, I, J, K, L1>,
687});
688tuples!(EitherOf13 + EitherOf13Future + EitherOf13FutureProj {
689    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>,
690    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>,
691    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>,
692    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>,
693    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>,
694    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>,
695    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>,
696    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>,
697    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>,
698    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>,
699    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>,
700    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>,
701    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>,
702});
703tuples!(EitherOf14 + EitherOf14Future + EitherOf14FutureProj {
704    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>,
705    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>,
706    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>,
707    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>,
708    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>,
709    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>,
710    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>,
711    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>,
712    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>,
713    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>,
714    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>,
715    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>,
716    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>,
717    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>,
718});
719tuples!(EitherOf15 + EitherOf15Future + EitherOf15FutureProj {
720    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>,
721    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>,
722    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>,
723    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>,
724    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>,
725    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>,
726    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>,
727    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>,
728    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>,
729    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>,
730    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>,
731    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>,
732    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>,
733    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>,
734    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>,
735});
736tuples!(EitherOf16 + EitherOf16Future + EitherOf16FutureProj {
737    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>,
738    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>,
739    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>,
740    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>,
741    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>,
742    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>,
743    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>,
744    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>,
745    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>,
746    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>,
747    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>,
748    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>,
749    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>,
750    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>,
751    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>,
752    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>,
753});
754
755/// Matches over the first expression and returns an either ([`Either`], [`EitherOf3`], ... [`EitherOf8`])
756/// composed of the values returned by the match arms.
757///
758/// The pattern syntax is exactly the same as found in a match arm.
759///
760/// # Examples
761///
762/// ```
763/// # use either_of::*;
764/// let either2 = either!(Some("hello"),
765///     Some(s) => s.len(),
766///     None => 0.0,
767/// );
768/// assert!(matches!(either2, Either::<usize, f64>::Left(5)));
769///
770/// let either3 = either!(Some("admin"),
771///     Some("admin") => "hello admin",
772///     Some(_) => 'x',
773///     _ => 0,
774/// );
775/// assert!(matches!(either3, EitherOf3::<&str, char, i32>::A("hello admin")));
776/// ```
777#[macro_export]
778macro_rules! either {
779    ($match:expr, $left_pattern:pat => $left_expression:expr, $right_pattern:pat => $right_expression:expr$(,)?) => {
780        match $match {
781            $left_pattern => $crate::Either::Left($left_expression),
782            $right_pattern => $crate::Either::Right($right_expression),
783        }
784    };
785    ($match:expr, $a_pattern:pat => $a_expression:expr, $b_pattern:pat => $b_expression:expr, $c_pattern:pat => $c_expression:expr$(,)?) => {
786        match $match {
787            $a_pattern => $crate::EitherOf3::A($a_expression),
788            $b_pattern => $crate::EitherOf3::B($b_expression),
789            $c_pattern => $crate::EitherOf3::C($c_expression),
790        }
791    };
792    ($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$(,)?) => {
793        match $match {
794            $a_pattern => $crate::EitherOf4::A($a_expression),
795            $b_pattern => $crate::EitherOf4::B($b_expression),
796            $c_pattern => $crate::EitherOf4::C($c_expression),
797            $d_pattern => $crate::EitherOf4::D($d_expression),
798        }
799    };
800    ($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$(,)?) => {
801        match $match {
802            $a_pattern => $crate::EitherOf5::A($a_expression),
803            $b_pattern => $crate::EitherOf5::B($b_expression),
804            $c_pattern => $crate::EitherOf5::C($c_expression),
805            $d_pattern => $crate::EitherOf5::D($d_expression),
806            $e_pattern => $crate::EitherOf5::E($e_expression),
807        }
808    };
809    ($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$(,)?) => {
810        match $match {
811            $a_pattern => $crate::EitherOf6::A($a_expression),
812            $b_pattern => $crate::EitherOf6::B($b_expression),
813            $c_pattern => $crate::EitherOf6::C($c_expression),
814            $d_pattern => $crate::EitherOf6::D($d_expression),
815            $e_pattern => $crate::EitherOf6::E($e_expression),
816            $f_pattern => $crate::EitherOf6::F($f_expression),
817        }
818    };
819    ($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$(,)?) => {
820        match $match {
821            $a_pattern => $crate::EitherOf7::A($a_expression),
822            $b_pattern => $crate::EitherOf7::B($b_expression),
823            $c_pattern => $crate::EitherOf7::C($c_expression),
824            $d_pattern => $crate::EitherOf7::D($d_expression),
825            $e_pattern => $crate::EitherOf7::E($e_expression),
826            $f_pattern => $crate::EitherOf7::F($f_expression),
827            $g_pattern => $crate::EitherOf7::G($g_expression),
828        }
829    };
830    ($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$(,)?) => {
831        match $match {
832            $a_pattern => $crate::EitherOf8::A($a_expression),
833            $b_pattern => $crate::EitherOf8::B($b_expression),
834            $c_pattern => $crate::EitherOf8::C($c_expression),
835            $d_pattern => $crate::EitherOf8::D($d_expression),
836            $e_pattern => $crate::EitherOf8::E($e_expression),
837            $f_pattern => $crate::EitherOf8::F($f_expression),
838            $g_pattern => $crate::EitherOf8::G($g_expression),
839            $h_pattern => $crate::EitherOf8::H($h_expression),
840        }
841    }; // if you need more eithers feel free to open a PR ;-)
842}
843
844#[cfg(test)]
845mod tests {
846    use super::*;
847
848    // compile time test
849    #[test]
850    fn either_macro() {
851        let _: Either<&str, f64> = either!(12,
852            12 => "12",
853            _ => 0.0,
854        );
855        let _: EitherOf3<&str, f64, i32> = either!(12,
856            12 => "12",
857            13 => 0.0,
858            _ => 12,
859        );
860        let _: EitherOf4<&str, f64, char, i32> = either!(12,
861            12 => "12",
862            13 => 0.0,
863            14 => ' ',
864            _ => 12,
865        );
866        let _: EitherOf5<&str, f64, char, f32, i32> = either!(12,
867            12 => "12",
868            13 => 0.0,
869            14 => ' ',
870            15 => 0.0f32,
871            _ => 12,
872        );
873        let _: EitherOf6<&str, f64, char, f32, u8, i32> = either!(12,
874            12 => "12",
875            13 => 0.0,
876            14 => ' ',
877            15 => 0.0f32,
878            16 => 24u8,
879            _ => 12,
880        );
881        let _: EitherOf7<&str, f64, char, f32, u8, i8, i32> = either!(12,
882            12 => "12",
883            13 => 0.0,
884            14 => ' ',
885            15 => 0.0f32,
886            16 => 24u8,
887            17 => 2i8,
888            _ => 12,
889        );
890        let _: EitherOf8<&str, f64, char, f32, u8, i8, u32, i32> = either!(12,
891            12 => "12",
892            13 => 0.0,
893            14 => ' ',
894            15 => 0.0f32,
895            16 => 24u8,
896            17 => 2i8,
897            18 => 42u32,
898            _ => 12,
899        );
900    }
901
902    #[test]
903    #[should_panic]
904    fn unwrap_wrong_either() {
905        Either::<i32, &str>::Left(0).unwrap_right();
906    }
907}