1use core::hash::BuildHasher;
2use std::collections::hash_map::Entry;
3use std::collections::hash_map::RandomState;
4use std::collections::HashMap;
5use std::fmt;
6use std::hash::Hash;
7use std::iter::FusedIterator;
8
9#[derive(Clone)]
13#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
14pub struct UniqueBy<I: Iterator, V, F, S = RandomState>
15where
16 S: BuildHasher,
17{
18 iter: I,
19 used: HashMap<V, (), S>,
23 f: F,
24}
25
26impl<I, V, F, S> fmt::Debug for UniqueBy<I, V, F, S>
27where
28 I: Iterator + fmt::Debug,
29 V: fmt::Debug + Hash + Eq,
30 S: BuildHasher,
31{
32 debug_fmt_fields!(UniqueBy, iter, used);
33}
34
35pub fn unique_by_with_hasher<I, V, F, S>(iter: I, f: F, hash_builder: S) -> UniqueBy<I, V, F, S>
37where
38 V: Eq + Hash,
39 F: FnMut(&I::Item) -> V,
40 I: Iterator,
41 S: BuildHasher,
42{
43 UniqueBy {
44 iter,
45 used: HashMap::with_hasher(hash_builder),
46 f,
47 }
48}
49
50fn count_new_keys<I, K, S>(mut used: HashMap<K, (), S>, iterable: I) -> usize
52where
53 I: IntoIterator<Item = K>,
54 K: Hash + Eq,
55 S: BuildHasher,
56{
57 let iter = iterable.into_iter();
58 let current_used = used.len();
59 used.extend(iter.map(|key| (key, ())));
60 used.len() - current_used
61}
62
63impl<I, V, F, S> Iterator for UniqueBy<I, V, F, S>
64where
65 I: Iterator,
66 V: Eq + Hash,
67 F: FnMut(&I::Item) -> V,
68 S: BuildHasher,
69{
70 type Item = I::Item;
71
72 fn next(&mut self) -> Option<Self::Item> {
73 let Self { iter, used, f } = self;
74 iter.find(|v| used.insert(f(v), ()).is_none())
75 }
76
77 #[inline]
78 fn size_hint(&self) -> (usize, Option<usize>) {
79 let (low, hi) = self.iter.size_hint();
80 (usize::from(low > 0 && self.used.is_empty()), hi)
81 }
82
83 fn count(self) -> usize {
84 let mut key_f = self.f;
85 count_new_keys(self.used, self.iter.map(move |elt| key_f(&elt)))
86 }
87}
88
89impl<I, V, F, S> DoubleEndedIterator for UniqueBy<I, V, F, S>
90where
91 I: DoubleEndedIterator,
92 V: Eq + Hash,
93 F: FnMut(&I::Item) -> V,
94 S: BuildHasher,
95{
96 fn next_back(&mut self) -> Option<Self::Item> {
97 let Self { iter, used, f } = self;
98 iter.rfind(|v| used.insert(f(v), ()).is_none())
99 }
100}
101
102impl<I, V, F, S> FusedIterator for UniqueBy<I, V, F, S>
103where
104 I: FusedIterator,
105 V: Eq + Hash,
106 F: FnMut(&I::Item) -> V,
107 S: BuildHasher,
108{
109}
110
111impl<I, S> Iterator for Unique<I, S>
112where
113 I: Iterator,
114 I::Item: Eq + Hash + Clone,
115 S: BuildHasher,
116{
117 type Item = I::Item;
118
119 fn next(&mut self) -> Option<Self::Item> {
120 let UniqueBy { iter, used, .. } = &mut self.iter;
121 iter.find_map(|v| {
122 if let Entry::Vacant(entry) = used.entry(v) {
123 let elt = entry.key().clone();
124 entry.insert(());
125 return Some(elt);
126 }
127 None
128 })
129 }
130
131 #[inline]
132 fn size_hint(&self) -> (usize, Option<usize>) {
133 let (low, hi) = self.iter.iter.size_hint();
134 (usize::from(low > 0 && self.iter.used.is_empty()), hi)
135 }
136
137 fn count(self) -> usize {
138 count_new_keys(self.iter.used, self.iter.iter)
139 }
140}
141
142impl<I, S> DoubleEndedIterator for Unique<I, S>
143where
144 I: DoubleEndedIterator,
145 I::Item: Eq + Hash + Clone,
146 S: BuildHasher,
147{
148 fn next_back(&mut self) -> Option<Self::Item> {
149 let UniqueBy { iter, used, .. } = &mut self.iter;
150 iter.rev().find_map(|v| {
151 if let Entry::Vacant(entry) = used.entry(v) {
152 let elt = entry.key().clone();
153 entry.insert(());
154 return Some(elt);
155 }
156 None
157 })
158 }
159}
160
161impl<I, S> FusedIterator for Unique<I, S>
162where
163 I: FusedIterator,
164 I::Item: Eq + Hash + Clone,
165 S: BuildHasher,
166{
167}
168
169#[derive(Clone)]
173#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
174pub struct Unique<I, S = RandomState>
175where
176 I: Iterator,
177 I::Item: Eq + Hash + Clone,
178 S: BuildHasher,
179{
180 iter: UniqueBy<I, I::Item, (), S>,
181}
182
183impl<I, S> fmt::Debug for Unique<I, S>
184where
185 I: Iterator + fmt::Debug,
186 I::Item: Hash + Eq + fmt::Debug + Clone,
187 S: BuildHasher,
188{
189 debug_fmt_fields!(Unique, iter);
190}
191
192pub fn unique_with_hasher<I, S>(iter: I, hash_builder: S) -> Unique<I, S>
193where
194 I: Iterator,
195 I::Item: Eq + Hash + Clone,
196 S: BuildHasher,
197{
198 Unique {
199 iter: UniqueBy {
200 iter,
201 used: HashMap::with_hasher(hash_builder),
202 f: (),
203 },
204 }
205}