core_extensions/iterators.rs
1//! Iterator adaptors and constructors.
2
3use std_::{
4 cmp::Ordering,
5 iter::{Product, Sum},
6 mem,
7};
8
9
10/// A version of [`std::iter::OnceWith`] usable in Rust 1.41.0.
11///
12/// # Example
13///
14/// ```
15/// use core_extensions::iterators::LazyOnce;
16///
17/// let mut number = 0;
18///
19/// // The closure here is never ran.
20/// LazyOnce::new(||{ number+=10; number });
21///
22/// assert_eq!(number, 0);
23///
24/// for i in LazyOnce::new(||{ number+=10; number }) {
25/// assert_eq!(i, 10);
26/// }
27///
28/// assert_eq!(number, 10);
29///
30/// ```
31///
32/// [`std::iter::OnceWith`]: https://doc.rust-lang.org/std/iter/struct.OnceWith.html
33/// [`Iterator::next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next
34///
35#[derive(Debug, Copy, Clone)]
36pub struct LazyOnce<F> {
37 func: Option<F>,
38}
39
40impl<F> LazyOnce<F> {
41 /// Constructs a LazyOnce.
42 pub fn new(f: F) -> Self {
43 LazyOnce { func: Some(f) }
44 }
45}
46
47impl<F, T> Iterator for LazyOnce<F>
48where
49 F: FnOnce() -> T,
50{
51 type Item = T;
52
53 fn next(&mut self) -> Option<T> {
54 self.func.take().map(|f| f())
55 }
56
57 fn size_hint(&self) -> (usize, Option<usize>) {
58 (1, Some(1))
59 }
60}
61
62impl<F, T> DoubleEndedIterator for LazyOnce<F>
63where
64 F: FnOnce() -> T,
65{
66 fn next_back(&mut self) -> Option<T> {
67 self.func.take().map(|f| f())
68 }
69}
70
71impl<F, T> ExactSizeIterator for LazyOnce<F> where F: FnOnce() -> T {}
72
73////////////////////////////////////////////////////////////////////////////////
74
75#[derive(Debug, Clone)]
76struct Unreplaced<T> {
77 nth: usize,
78 current: usize,
79 with: T,
80}
81
82#[derive(Debug, Clone)]
83enum ReplaceNthState<T> {
84 Unreplaced(Unreplaced<T>),
85 Replaced,
86}
87
88/// An Iterator that replaces the `nth` element with another value.
89///
90/// # Example
91///
92/// ```rust
93/// use core_extensions::iterators::ReplaceNth;
94///
95/// // This iterator replaces the 4th element with `100`
96/// let list = ReplaceNth::new(0..=6, 4, 100).collect::<Vec<_>>();
97///
98/// assert_eq!(list, vec![0, 1, 2, 3, 100, 5, 6]);
99///
100/// ```
101///
102#[derive(Debug, Clone)]
103pub struct ReplaceNth<I>
104where
105 I: Iterator,
106{
107 iter: I,
108 state: ReplaceNthState<I::Item>,
109}
110
111impl<I> ReplaceNth<I>
112where
113 I: Iterator,
114{
115 /// Constructs a `ReplaceNth`.
116 pub fn new(iter: I, nth: usize, with: I::Item) -> Self {
117 Self {
118 iter,
119 state: ReplaceNthState::Unreplaced(Unreplaced {
120 nth,
121 current: 0,
122 with,
123 }),
124 }
125 }
126}
127
128impl<I> Iterator for ReplaceNth<I>
129where
130 I: Iterator,
131{
132 type Item = I::Item;
133
134 fn next(&mut self) -> Option<I::Item> {
135 use self::ReplaceNthState as RNS;
136
137 let mut ret = self.iter.next()?;
138
139 let replace = match self.state {
140 RNS::Unreplaced(ref mut unreplaced) => {
141 let x = unreplaced.nth == unreplaced.current;
142 if !x {
143 unreplaced.current += 1
144 }
145 x
146 }
147 RNS::Replaced => false,
148 };
149 if replace {
150 if let RNS::Unreplaced(unreplaced) = mem::replace(&mut self.state, RNS::Replaced) {
151 ret = unreplaced.with;
152 }
153 }
154 Some(ret)
155 }
156
157 fn nth(&mut self, nth: usize) -> Option<I::Item> {
158 use self::ReplaceNthState as RNS;
159
160 let mut ret = self.iter.nth(nth)?;
161
162 let mut replace = Ordering::Greater;
163 if let RNS::Unreplaced(ref mut unreplaced) = self.state {
164 unreplaced.current += nth;
165 replace = unreplaced.current.cmp(&unreplaced.nth);
166 if replace == Ordering::Less {
167 unreplaced.current += 1;
168 }
169 }
170 match replace {
171 Ordering::Less => {}
172 Ordering::Equal => {
173 if let RNS::Unreplaced(unreplaced) = mem::replace(&mut self.state, RNS::Replaced) {
174 ret = unreplaced.with;
175 }
176 }
177 Ordering::Greater => self.state = RNS::Replaced,
178 }
179 Some(ret)
180 }
181
182 fn size_hint(&self) -> (usize, Option<usize>) {
183 self.iter.size_hint()
184 }
185
186 fn count(self) -> usize {
187 self.iter.count()
188 }
189}
190
191#[cfg(test)]
192#[cfg(feature = "alloc")]
193mod test_replace_nth {
194 use super::*;
195 #[test]
196 fn nth_method() {
197 let list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
198
199 for i in 0..list.len() {
200 let mut iter = ReplaceNth::new(list.iter().cloned(), i, 100);
201 if i != 0 {
202 let j = i - 1;
203 assert_eq!(iter.nth(j).unwrap(), list[j])
204 }
205 assert_eq!(iter.next().unwrap(), 100);
206 if i + 1 < list.len() {
207 assert_eq!(iter.next().unwrap(), list[i + 1]);
208 }
209 if i + 2 < list.len() {
210 assert_eq!(iter.next().unwrap(), list[i + 2]);
211 }
212 }
213 }
214}
215
216////////////////////////////////////////////////////////////////////////////////
217
218/// Extension trait for [`std::iter::Iterator`] implementors.
219///
220/// [`std::iter::Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
221pub trait IteratorExt: Iterator {
222 /// Collects into an existing collection by extending it.
223 ///
224 /// # Example
225 ///
226 /// ```
227 /// use core_extensions::iterators::IteratorExt;
228 ///
229 /// let mut list = vec![101, 102];
230 ///
231 /// (0..10)
232 /// .filter(|&v| v<5 )
233 /// .map(|v| v*2 )
234 /// .extending(&mut list);
235 ///
236 /// assert_eq!(list, vec![101, 102, 0, 2, 4, 6, 8]);
237 ///
238 /// ```
239 #[inline(always)]
240 fn extending<C>(self, extend: &mut C)
241 where
242 Self: Sized,
243 C: Extend<Self::Item>,
244 {
245 extend.extend(self);
246 }
247
248 /// Collects into a pre-allocated collection,returning it by value.
249 ///
250 /// # Example
251 ///
252 /// ```
253 /// use core_extensions::iterators::IteratorExt;
254 ///
255 /// let list = (0..10)
256 /// .filter(|&v| v<5 )
257 /// .map(|v| v*2 )
258 /// .collect_into(Vec::with_capacity(5));
259 ///
260 /// assert_eq!(list.capacity(), 5);
261 /// assert_eq!(list, vec![0, 2, 4, 6, 8]);
262 ///
263 /// ```
264 /// # Example
265 ///
266 /// Reusing an existing collection.
267 ///
268 /// ```
269 /// use core_extensions::iterators::IteratorExt;
270 ///
271 /// let mut list = Vec::with_capacity(7);
272 /// list.push(100);
273 /// list.push(101);
274 ///
275 /// let list = (0..10)
276 /// .filter(|&v| v<5 )
277 /// .map(|v| v*2 )
278 /// .collect_into(list);
279 ///
280 /// assert_eq!(list.capacity(),7);
281 /// assert_eq!(list, vec![100, 101, 0, 2, 4, 6, 8]);
282 ///
283 /// ```
284 #[inline(always)]
285 fn collect_into<C>(self, mut extend: C) -> C
286 where
287 Self: Sized,
288 C: Extend<Self::Item>,
289 {
290 extend.extend(self);
291 extend
292 }
293
294 /// An Iterator that replaces the nth element with another value.
295 ///
296 /// # Example
297 /// ```
298 /// use core_extensions::iterators::IteratorExt;
299 ///
300 /// assert_eq!(
301 /// (0..=9).replace_nth(5, 1337).collect::<Vec<_>>(),
302 /// vec![0, 1, 2, 3, 4, 1337, 6, 7, 8, 9]
303 /// );
304 ///
305 /// let list = vec!["hello", "dear", "world"];
306 ///
307 /// assert_eq!(
308 /// list.into_iter().replace_nth(1, "my").collect::<Vec<_>>(),
309 /// vec!["hello", "my", "world"]
310 /// );
311 ///
312 ///
313 /// ```
314 #[inline(always)]
315 fn replace_nth(self, nth: usize, with: Self::Item) -> ReplaceNth<Self>
316 where
317 Self: Sized,
318 {
319 ReplaceNth::new(self, nth, with)
320 }
321
322 /// Sums the items of the iterator, into the item's type.
323 ///
324 /// This like the [`Iterator::sum`] method, with better type inference,
325 /// since with the [`Iterator::sum`] method you must specify its return type.
326 ///
327 /// # Example
328 ///
329 /// ```rust
330 /// use core_extensions::iterators::IteratorExt;
331 ///
332 /// assert_eq!((1..=4).sum_same(), 10);
333 ///
334 /// let arr = [3, 7, 11, 29];
335 /// assert_eq!(arr.iter().copied().sum_same(), 50);
336 ///
337 /// ```
338 ///
339 /// [`Iterator::sum`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum
340 #[inline]
341 fn sum_same(self) -> Self::Item
342 where
343 Self: Sized,
344 Self::Item: Sum,
345 {
346 <Self::Item as Sum<Self::Item>>::sum(self)
347 }
348
349 /// Multiplies the items of the iterator, into the item's type.
350 ///
351 /// This like the [`Iterator::product`] method, with better type inference,
352 /// since with the [`Iterator::product`] method you must specify its return type.
353 ///
354 /// # Example
355 ///
356 /// ```rust
357 /// use core_extensions::iterators::IteratorExt;
358 ///
359 /// assert_eq!((1..=4).product_same(), 24);
360 ///
361 /// let arr = [3, 4, 6];
362 /// assert_eq!(arr.iter().copied().product_same(), 72);
363 ///
364 /// ```
365 ///
366 /// [`Iterator::product`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.product
367 #[inline]
368 fn product_same(self) -> Self::Item
369 where
370 Self: Sized,
371 Self::Item: Product,
372 {
373 <Self::Item as Product<Self::Item>>::product(self)
374 }
375}
376
377impl<I> IteratorExt for I where I: ?Sized + Iterator {}
378
379////////////////////////////////////////////////////////////////////////////////
380
381/// Uses a closure to construct `Iterator`s.
382///
383/// This can turn this into an `Iterator` (with `IntoIterator::into_iter`)
384/// multiple times if the closure is `Copy`.
385///
386/// # Example
387///
388/// ```rust
389/// use core_extensions::iterators::IterConstructor;
390///
391/// let list = vec!["hello", "world"];
392///
393/// let constructor = IterConstructor(||{
394/// list.iter().enumerate().map(|(i,v)| v.repeat(i) )
395/// });
396///
397/// for _ in 0..2 {
398/// assert_eq!(
399/// constructor.into_iter().collect::<Vec<_>>(),
400/// ["".to_string(), "world".to_string()],
401/// );
402/// }
403///
404/// ```
405#[derive(Debug, Copy, Clone)]
406pub struct IterConstructor<F> (pub F);
407
408impl<F, I> IntoIterator for IterConstructor<F>
409where
410 F: FnOnce() -> I,
411 I: IntoIterator,
412{
413 type Item = I::Item;
414 type IntoIter = I::IntoIter;
415
416 #[inline]
417 fn into_iter(self) -> Self::IntoIter {
418 (self.0)().into_iter()
419 }
420}
421
422////////////////////////////////////////////////////////////////////////////////
423
424/// Use this macro to create an
425/// [`IterCloner`](./iterators/struct.IterCloner.html)
426/// from an [`IntoIterator`] (this includes all [`Iterator`]s).
427///
428/// The resulting variable clones the iterator (that `$expr` was converted into)
429/// every time that you call `.into_iter()` or iterate over it with a `for` loop.
430///
431/// # Example
432///
433/// ### Mapping
434///
435/// ```rust
436/// use core_extensions::iter_cloner;
437///
438/// let list = vec!["this", "is", "not", "really", "great"];
439///
440/// let lengths = vec![4, 2, 3, 6, 5];
441///
442/// iter_cloner!(let iter = list.iter().map(|v|v.len()));
443///
444/// assert_eq!(iter.into_iter().collect::<Vec<_>>(), lengths);
445/// assert_eq!(iter.into_iter().collect::<Vec<_>>(), lengths);
446/// assert_eq!(iter.into_iter().collect::<Vec<_>>(), lengths);
447///
448/// ```
449///
450/// ### Vector
451///
452/// ```rust
453/// use core_extensions::iter_cloner;
454///
455/// iter_cloner!(let iter = vec![0, 1, 2, 3]);
456///
457/// assert_eq!(iter.into_iter().collect::<Vec<_>>(), [0, 1, 2, 3]);
458/// assert_eq!(iter.into_iter().collect::<Vec<_>>(), [0, 1, 2, 3]);
459/// assert_eq!(iter.into_iter().collect::<Vec<_>>(), [0, 1, 2, 3]);
460///
461/// ```
462///
463/// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
464/// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
465#[cfg(feature = "iterators")]
466#[cfg_attr(feature = "docsrs", doc(cfg(feature = "iterators")))]
467#[macro_export]
468macro_rules! iter_cloner {
469 (let $ident:ident = $expr:expr) => {
470 let $ident = $crate::std_::iter::IntoIterator::into_iter($expr);
471 let $ident = $crate::iterators::IterCloner(&$ident);
472 };
473}
474
475/// Implements [`IntoIterator::into_iter`] by cloning the iterator it references.
476///
477/// You can also use the [`iter_cloner`](../macro.iter_cloner.html) macro to
478/// construct this,
479///
480/// # Example
481///
482/// ```
483///
484/// use core_extensions::iterators::IterCloner;
485///
486/// let list = vec!["hello", "awesome", "world"];
487///
488/// let iter = list.iter().map(|v|v.len()).filter(|&v| v<6 );
489///
490/// let iter_clone = IterCloner(&iter);
491///
492/// for _ in 0..2{
493/// assert_eq!(iter_clone.into_iter().collect::<Vec<_>>(), vec![5, 5]);
494/// }
495///
496/// ```
497///
498/// [`IntoIterator::into_iter`]:
499/// https://doc.rust-lang.org/std/iter/trait.IntoIterator.html#tymethod.into_iter
500///
501#[derive(Debug)]
502pub struct IterCloner<'a, I: 'a> (pub &'a I);
503
504impl<'a, I> Copy for IterCloner<'a, I> {}
505impl<'a, I> Clone for IterCloner<'a, I> {
506 fn clone(&self) -> Self {
507 *self
508 }
509}
510
511impl<'a, I: 'a> IntoIterator for IterCloner<'a, I>
512where
513 I: Iterator + Clone,
514{
515 type Item = I::Item;
516 type IntoIter = I;
517
518 fn into_iter(self) -> Self::IntoIter {
519 self.0.clone()
520 }
521}