intersperse.rs - source
Description: Source of the Rust file `library/core/src/iter/adapters/intersperse.rs`.

#
core/iter/adapters/
intersperse.rs

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