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}