nonempty_collections/
either.rs

1//! Extension of [`either::Either`] to provide support for [`NonEmptyIterator`].
2//!
3//! ```
4//! use nonempty_collections::*;
5//! fn get_data(input: usize) -> NEEither<[usize; 1], [usize; 3]> {
6//!     if input == 0 {
7//!         NEEither::Left([0])
8//!     } else {
9//!         NEEither::Right([2, 1, 4])
10//!     }
11//! }
12//!
13//! assert_eq!(
14//!     nev![0],
15//!     get_data(0).into_nonempty_iter().collect::<NEVec<_>>()
16//! );
17//! ```
18
19// Implementation note:
20// In an ideal world there is no need for `NEEither` and we could just implement
21// `NonEmptyIterator` for `Either`. However, the following holds:
22//  - `NonEmptyIterator` requires an implementation of `IntoIterator`
23//  - `Either` conditionally implements `Iterator`
24//  - Rust has blanket implementation `impl<I: Iterator> IntoIterator for I`
25// Therefore we cannot implement (`Into`)`NonEmptyIterator` for `Either<L, R>`
26// except if we add bounds similar to `L: NonEmptyIterator + Iterator` and `R:
27// NonEmptyIterator + Iterator`, which our implementations of `NonEmptyIterator`
28// don't satisfy as that would break encapsulation.
29
30use either::Either;
31
32use crate::IntoNonEmptyIterator;
33use crate::NonEmptyIterator;
34
35/// Non-empty variant of [`either::Either`] that implements
36/// [`NonEmptyIterator`].
37#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
38pub enum NEEither<L, R> {
39    /// A value of type `L`.
40    Left(L),
41    /// A value of type `R`.
42    Right(R),
43}
44
45impl<L, R> NEEither<L, R> {
46    /// Convert the inner value to a `NonEmptyIterator`.
47    ///
48    /// This requires the `Left` and `Right` non-empty iterators to have the
49    /// same item type.
50    ///
51    /// ```
52    /// use nonempty_collections::*;
53    /// let left: NEEither<_, NESet<usize>> = NEEither::Left(nev![1, 2, 3]);
54    /// let right: NEEither<NEVec<usize>, _> = NEEither::Right(nes![4]);
55    ///
56    /// let combined = left.into_nonempty_iter().chain(right).collect::<NEVec<_>>();
57    /// let expected = nev![1, 2, 3, 4];
58    /// assert_eq!(expected, combined);
59    /// ```
60    pub fn into_nonempty_iter(self) -> NEEither<L::IntoNEIter, R::IntoNEIter>
61    where
62        L: IntoNonEmptyIterator,
63        R: IntoNonEmptyIterator<Item = L::Item>,
64    {
65        match self {
66            NEEither::Left(left) => NEEither::Left(left.into_nonempty_iter()),
67            NEEither::Right(right) => NEEither::Right(right.into_nonempty_iter()),
68        }
69    }
70}
71
72impl<L, R> NonEmptyIterator for NEEither<L, R>
73where
74    L: NonEmptyIterator + IntoIterator,
75    R: NonEmptyIterator + IntoIterator<Item = L::Item>,
76{
77}
78
79impl<L, R> IntoIterator for NEEither<L, R>
80where
81    L: IntoIterator,
82    R: IntoIterator<Item = L::Item>,
83{
84    type Item = L::Item;
85
86    type IntoIter = Either<L::IntoIter, R::IntoIter>;
87
88    fn into_iter(self) -> Self::IntoIter {
89        match self {
90            NEEither::Left(left) => Either::Left(left.into_iter()),
91            NEEither::Right(right) => Either::Right(right.into_iter()),
92        }
93    }
94}