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