itertools/
pad_tail.rs

1use crate::size_hint;
2use std::iter::{Fuse, FusedIterator};
3
4/// An iterator adaptor that pads a sequence to a minimum length by filling
5/// missing elements using a closure.
6///
7/// Iterator element type is `I::Item`.
8///
9/// See [`.pad_using()`](crate::Itertools::pad_using) for more information.
10#[derive(Clone)]
11#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
12pub struct PadUsing<I, F> {
13    iter: Fuse<I>,
14    min: usize,
15    pos: usize,
16    filler: F,
17}
18
19impl<I, F> std::fmt::Debug for PadUsing<I, F>
20where
21    I: std::fmt::Debug,
22{
23    debug_fmt_fields!(PadUsing, iter, min, pos);
24}
25
26/// Create a new `PadUsing` iterator.
27pub fn pad_using<I, F>(iter: I, min: usize, filler: F) -> PadUsing<I, F>
28where
29    I: Iterator,
30    F: FnMut(usize) -> I::Item,
31{
32    PadUsing {
33        iter: iter.fuse(),
34        min,
35        pos: 0,
36        filler,
37    }
38}
39
40impl<I, F> Iterator for PadUsing<I, F>
41where
42    I: Iterator,
43    F: FnMut(usize) -> I::Item,
44{
45    type Item = I::Item;
46
47    #[inline]
48    fn next(&mut self) -> Option<Self::Item> {
49        match self.iter.next() {
50            None => {
51                if self.pos < self.min {
52                    let e = Some((self.filler)(self.pos));
53                    self.pos += 1;
54                    e
55                } else {
56                    None
57                }
58            }
59            e => {
60                self.pos += 1;
61                e
62            }
63        }
64    }
65
66    fn size_hint(&self) -> (usize, Option<usize>) {
67        let tail = self.min.saturating_sub(self.pos);
68        size_hint::max(self.iter.size_hint(), (tail, Some(tail)))
69    }
70
71    fn fold<B, G>(self, mut init: B, mut f: G) -> B
72    where
73        G: FnMut(B, Self::Item) -> B,
74    {
75        let mut pos = self.pos;
76        init = self.iter.fold(init, |acc, item| {
77            pos += 1;
78            f(acc, item)
79        });
80        (pos..self.min).map(self.filler).fold(init, f)
81    }
82}
83
84impl<I, F> DoubleEndedIterator for PadUsing<I, F>
85where
86    I: DoubleEndedIterator + ExactSizeIterator,
87    F: FnMut(usize) -> I::Item,
88{
89    fn next_back(&mut self) -> Option<Self::Item> {
90        if self.min == 0 {
91            self.iter.next_back()
92        } else if self.iter.len() >= self.min {
93            self.min -= 1;
94            self.iter.next_back()
95        } else {
96            self.min -= 1;
97            Some((self.filler)(self.min))
98        }
99    }
100
101    fn rfold<B, G>(self, mut init: B, mut f: G) -> B
102    where
103        G: FnMut(B, Self::Item) -> B,
104    {
105        init = (self.iter.len()..self.min)
106            .map(self.filler)
107            .rfold(init, &mut f);
108        self.iter.rfold(init, f)
109    }
110}
111
112impl<I, F> ExactSizeIterator for PadUsing<I, F>
113where
114    I: ExactSizeIterator,
115    F: FnMut(usize) -> I::Item,
116{
117}
118
119impl<I, F> FusedIterator for PadUsing<I, F>
120where
121    I: FusedIterator,
122    F: FnMut(usize) -> I::Item,
123{
124}