summaryrefslogtreecommitdiffstats
path: root/third_party/rust/itertools/src/pad_tail.rs
blob: 248a4324368a22fa0ff49e1194ab7fdde43ec6ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use std::iter::{Fuse, FusedIterator};
use crate::size_hint;

/// An iterator adaptor that pads a sequence to a minimum length by filling
/// missing elements using a closure.
///
/// Iterator element type is `I::Item`.
///
/// See [`.pad_using()`](crate::Itertools::pad_using) for more information.
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct PadUsing<I, F> {
    iter: Fuse<I>,
    min: usize,
    pos: usize,
    filler: F,
}

impl<I, F> std::fmt::Debug for PadUsing<I, F>
where
    I: std::fmt::Debug,
{
    debug_fmt_fields!(PadUsing, iter, min, pos);
}

/// Create a new `PadUsing` iterator.
pub fn pad_using<I, F>(iter: I, min: usize, filler: F) -> PadUsing<I, F>
    where I: Iterator,
          F: FnMut(usize) -> I::Item
{
    PadUsing {
        iter: iter.fuse(),
        min,
        pos: 0,
        filler,
    }
}

impl<I, F> Iterator for PadUsing<I, F>
    where I: Iterator,
          F: FnMut(usize) -> I::Item
{
    type Item = I::Item;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        match self.iter.next() {
            None => {
                if self.pos < self.min {
                    let e = Some((self.filler)(self.pos));
                    self.pos += 1;
                    e
                } else {
                    None
                }
            },
            e => {
                self.pos += 1;
                e
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let tail = self.min.saturating_sub(self.pos);
        size_hint::max(self.iter.size_hint(), (tail, Some(tail)))
    }
}

impl<I, F> DoubleEndedIterator for PadUsing<I, F>
    where I: DoubleEndedIterator + ExactSizeIterator,
          F: FnMut(usize) -> I::Item
{
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.min == 0 {
            self.iter.next_back()
        } else if self.iter.len() >= self.min {
            self.min -= 1;
            self.iter.next_back()
        } else {
            self.min -= 1;
            Some((self.filler)(self.min))
        }
    }
}

impl<I, F> ExactSizeIterator for PadUsing<I, F>
    where I: ExactSizeIterator,
          F: FnMut(usize) -> I::Item
{}


impl<I, F> FusedIterator for PadUsing<I, F>
    where I: FusedIterator,
          F: FnMut(usize) -> I::Item
{}