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
use super::Peekable;

/// An iterator adapter that places a separator between all elements.
#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
#[derive(Debug, Clone)]
pub struct Intersperse<I: Iterator>
where
    I::Item: Clone,
{
    separator: I::Item,
    iter: Peekable<I>,
    needs_sep: bool,
}

impl<I: Iterator> Intersperse<I>
where
    I::Item: Clone,
{
    pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self {
        Self { iter: iter.peekable(), separator, needs_sep: false }
    }
}

#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
impl<I> Iterator for Intersperse<I>
where
    I: Iterator,
    I::Item: Clone,
{
    type Item = I::Item;

    #[inline]
    fn next(&mut self) -> Option<I::Item> {
        if self.needs_sep && self.iter.peek().is_some() {
            self.needs_sep = false;
            Some(self.separator.clone())
        } else {
            self.needs_sep = true;
            self.iter.next()
        }
    }

    fn fold<B, F>(mut self, init: B, mut f: F) -> B
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> B,
    {
        let mut accum = init;

        // Use `peek()` first to avoid calling `next()` on an empty iterator.
        if !self.needs_sep || self.iter.peek().is_some() {
            if let Some(x) = self.iter.next() {
                accum = f(accum, x);
            }
        }

        let element = &self.separator;

        self.iter.fold(accum, |mut accum, x| {
            accum = f(accum, element.clone());
            accum = f(accum, x);
            accum
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (lo, hi) = self.iter.size_hint();
        let next_is_elem = !self.needs_sep;
        let lo = lo.saturating_sub(next_is_elem as usize).saturating_add(lo);
        let hi = match hi {
            Some(hi) => hi.saturating_sub(next_is_elem as usize).checked_add(hi),
            None => None,
        };
        (lo, hi)
    }
}