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}