nonempty_collections/
itertools.rs

1//! Extra non-empty iterator adaptors, functions and macros.
2//!
3//! To extend [`NonEmptyIterator`] with methods in this crate, import
4//! the [`NonEmptyItertools`] trait:
5//!
6//! ```
7//! use nonempty_collections::NonEmptyItertools;
8//! ```
9
10use crate::IntoNonEmptyIterator;
11use crate::NonEmptyIterator;
12use core::fmt;
13use itertools::Itertools;
14use std::fmt::Debug;
15
16/// A [`NonEmptyIterator`] blanket implementation that provides extra adaptors
17/// and methods, similar to [`Itertools`](https://docs.rs/itertools/) for `Iterator`.
18pub trait NonEmptyItertools: NonEmptyIterator {
19    /// Return a non-empty iterator adaptor that iterates over the non-empty
20    /// cartesian product of the element sets of two iterators `self` and
21    /// `J`.
22    ///
23    /// `NonEmptyIterator`element type is `(Self::Item, J::Item)`.
24    ///
25    /// ```
26    /// use nonempty_collections::*;
27    ///
28    /// let product = nev![0, 1]
29    ///     .nonempty_iter()
30    ///     .copied()
31    ///     .cartesian_product("αβ".chars().try_into_nonempty_iter().unwrap())
32    ///     .collect::<NEVec<_>>();
33    /// assert_eq!(nev![(0, 'α'), (0, 'β'), (1, 'α'), (1, 'β')], product);
34    /// ```
35    fn cartesian_product<J>(self, other: J) -> Product<Self, J::IntoNEIter>
36    where
37        Self: Sized,
38        Self::Item: Clone,
39        J: IntoNonEmptyIterator,
40        <J::IntoNEIter as IntoIterator>::IntoIter: Clone,
41    {
42        Product {
43            inner: Itertools::cartesian_product(self.into_iter(), other.into_nonempty_iter()),
44        }
45    }
46
47    /// Check whether all elements are unique (non equal).
48    ///
49    /// # Examples
50    ///
51    /// ```
52    /// use nonempty_collections::*;
53    ///
54    /// let data = nev![1, 2, 3, 4, 1, 5];
55    /// assert!(!nev![1, 2, 3, 4, 1, 5].nonempty_iter().all_unique());
56    /// assert!(nev![2, 3, 4, 1, 5].nonempty_iter().all_unique());
57    /// ```
58    #[must_use]
59    fn all_unique(self) -> bool
60    where
61        Self: Sized,
62        Self::Item: Eq + std::hash::Hash,
63    {
64        self.into_iter().all_unique()
65    }
66}
67
68impl<T> NonEmptyItertools for T where T: NonEmptyIterator + ?Sized {}
69
70/// A non-empty iterator adaptor that iterates over the cartesian product of
71/// the element sets of two iterators `I` and `J`.
72///
73/// Iterator element type is `(I::Item, J::Item)`.
74///
75/// See [`.cartesian_product()`](crate::itertools::Itertools::cartesian_product)
76/// for more information.
77#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
78pub struct Product<I, J>
79where
80    I: NonEmptyIterator,
81    J: NonEmptyIterator,
82{
83    inner: itertools::Product<I::IntoIter, J::IntoIter>,
84}
85
86impl<I, J> NonEmptyIterator for Product<I, J>
87where
88    I: NonEmptyIterator,
89    J: NonEmptyIterator,
90    J::Item: Clone,
91    I::Item: Clone,
92    J::IntoIter: Clone,
93    I::IntoIter: Clone,
94{
95}
96
97impl<I, J> IntoIterator for Product<I, J>
98where
99    I: NonEmptyIterator,
100    J: NonEmptyIterator,
101    J::Item: Clone,
102    I::Item: Clone,
103    J::IntoIter: Clone,
104    I::IntoIter: Clone,
105{
106    type Item = (I::Item, J::Item);
107
108    type IntoIter = itertools::Product<I::IntoIter, J::IntoIter>;
109
110    fn into_iter(self) -> Self::IntoIter {
111        self.inner
112    }
113}
114
115impl<I, J> Debug for Product<I, J>
116where
117    I: NonEmptyIterator,
118    J: NonEmptyIterator,
119    I::Item: Debug,
120    J::Item: Debug,
121    I::IntoIter: Debug,
122    J::IntoIter: Debug,
123{
124    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125        Debug::fmt(&self.inner, f)
126    }
127}