Skip to main content

core/iter/adapters/
intersperse.rs

1use crate::fmt;
2
3/// An iterator adapter that places a separator between all elements.
4///
5/// This `struct` is created by [`Iterator::intersperse`]. See its documentation
6/// for more information.
7#[unstable(feature = "iter_intersperse", issue = "79524")]
8#[derive(Debug, Clone)]
9pub struct Intersperse<I: Iterator>
10where
11    I::Item: Clone,
12{
13    started: bool,
14    separator: I::Item,
15    next_item: Option<I::Item>,
16    iter: I,
17}
18
19impl<I: Iterator> Intersperse<I>
20where
21    I::Item: Clone,
22{
23    pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self {
24        Self { started: false, separator, next_item: None, iter }
25    }
26}
27
28#[unstable(feature = "iter_intersperse", issue = "79524")]
29impl<I> Iterator for Intersperse<I>
30where
31    I: Iterator,
32    I::Item: Clone,
33{
34    type Item = I::Item;
35
36    #[inline]
37    fn next(&mut self) -> Option<Self::Item> {
38        if self.started {
39            if let Some(v) = self.next_item.take() {
40                Some(v)
41            } else {
42                let next_item = self.iter.next();
43                if next_item.is_some() {
44                    self.next_item = next_item;
45                    Some(self.separator.clone())
46                } else {
47                    None
48                }
49            }
50        } else {
51            let item = self.iter.next();
52            self.started = item.is_some();
53            item
54        }
55    }
56
57    fn size_hint(&self) -> (usize, Option<usize>) {
58        intersperse_size_hint(&self.iter, self.started, self.next_item.is_some())
59    }
60
61    fn fold<B, F>(self, init: B, f: F) -> B
62    where
63        Self: Sized,
64        F: FnMut(B, Self::Item) -> B,
65    {
66        let separator = self.separator;
67        intersperse_fold(
68            self.iter,
69            init,
70            f,
71            move || separator.clone(),
72            self.started,
73            self.next_item,
74        )
75    }
76}
77
78/// An iterator adapter that places a separator between all elements.
79///
80/// This `struct` is created by [`Iterator::intersperse_with`]. See its
81/// documentation for more information.
82#[unstable(feature = "iter_intersperse", issue = "79524")]
83pub struct IntersperseWith<I, G>
84where
85    I: Iterator,
86{
87    started: bool,
88    separator: G,
89    next_item: Option<I::Item>,
90    iter: I,
91}
92
93#[unstable(feature = "iter_intersperse", issue = "79524")]
94impl<I, G> fmt::Debug for IntersperseWith<I, G>
95where
96    I: Iterator + fmt::Debug,
97    I::Item: fmt::Debug,
98    G: fmt::Debug,
99{
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        f.debug_struct("IntersperseWith")
102            .field("started", &self.started)
103            .field("separator", &self.separator)
104            .field("iter", &self.iter)
105            .field("next_item", &self.next_item)
106            .finish()
107    }
108}
109
110#[unstable(feature = "iter_intersperse", issue = "79524")]
111impl<I, G> Clone for IntersperseWith<I, G>
112where
113    I: Iterator + Clone,
114    I::Item: Clone,
115    G: Clone,
116{
117    fn clone(&self) -> Self {
118        Self {
119            started: self.started,
120            separator: self.separator.clone(),
121            iter: self.iter.clone(),
122            next_item: self.next_item.clone(),
123        }
124    }
125}
126
127impl<I, G> IntersperseWith<I, G>
128where
129    I: Iterator,
130    G: FnMut() -> I::Item,
131{
132    pub(in crate::iter) fn new(iter: I, separator: G) -> Self {
133        Self { started: false, separator, next_item: None, iter }
134    }
135}
136
137#[unstable(feature = "iter_intersperse", issue = "79524")]
138impl<I, G> Iterator for IntersperseWith<I, G>
139where
140    I: Iterator,
141    G: FnMut() -> I::Item,
142{
143    type Item = I::Item;
144
145    #[inline]
146    fn next(&mut self) -> Option<Self::Item> {
147        if self.started {
148            if let Some(v) = self.next_item.take() {
149                Some(v)
150            } else {
151                let next_item = self.iter.next();
152                if next_item.is_some() {
153                    self.next_item = next_item;
154                    Some((self.separator)())
155                } else {
156                    None
157                }
158            }
159        } else {
160            let item = self.iter.next();
161            self.started = item.is_some();
162            item
163        }
164    }
165
166    fn size_hint(&self) -> (usize, Option<usize>) {
167        intersperse_size_hint(&self.iter, self.started, self.next_item.is_some())
168    }
169
170    fn fold<B, F>(self, init: B, f: F) -> B
171    where
172        Self: Sized,
173        F: FnMut(B, Self::Item) -> B,
174    {
175        intersperse_fold(self.iter, init, f, self.separator, self.started, self.next_item)
176    }
177}
178
179fn intersperse_size_hint<I>(iter: &I, started: bool, next_is_some: bool) -> (usize, Option<usize>)
180where
181    I: Iterator,
182{
183    let (lo, hi) = iter.size_hint();
184    (
185        lo.saturating_sub(!started as usize)
186            .saturating_add(next_is_some as usize)
187            .saturating_add(lo),
188        hi.and_then(|hi| {
189            hi.saturating_sub(!started as usize)
190                .saturating_add(next_is_some as usize)
191                .checked_add(hi)
192        }),
193    )
194}
195
196fn intersperse_fold<I, B, F, G>(
197    mut iter: I,
198    init: B,
199    mut f: F,
200    mut separator: G,
201    started: bool,
202    mut next_item: Option<I::Item>,
203) -> B
204where
205    I: Iterator,
206    F: FnMut(B, I::Item) -> B,
207    G: FnMut() -> I::Item,
208{
209    let mut accum = init;
210
211    let first = if started {
212        next_item.take()
213    } else {
214        let n = iter.next();
215        // skip invoking fold() for empty iterators
216        if n.is_none() {
217            return accum;
218        }
219        n
220    };
221    if let Some(x) = first {
222        accum = f(accum, x);
223    }
224
225    iter.fold(accum, |mut accum, x| {
226        accum = f(accum, separator());
227        accum = f(accum, x);
228        accum
229    })
230}