use crate::fmt; use crate::iter::{Fuse, FusedIterator}; /// An iterator adapter that places a separator between all elements. /// /// This `struct` is created by [`Iterator::intersperse`]. See its documentation /// for more information. #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] #[derive(Debug, Clone)] pub struct Intersperse where I::Item: Clone, { started: bool, separator: I::Item, next_item: Option, iter: Fuse, } #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] impl FusedIterator for Intersperse where I: FusedIterator, I::Item: Clone, { } impl Intersperse where I::Item: Clone, { pub(in crate::iter) fn new(iter: I, separator: I::Item) -> Self { Self { started: false, separator, next_item: None, iter: iter.fuse() } } } #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] impl Iterator for Intersperse where I: Iterator, I::Item: Clone, { type Item = I::Item; #[inline] fn next(&mut self) -> Option { if self.started { if let Some(v) = self.next_item.take() { Some(v) } else { let next_item = self.iter.next(); if next_item.is_some() { self.next_item = next_item; Some(self.separator.clone()) } else { None } } } else { self.started = true; self.iter.next() } } fn size_hint(&self) -> (usize, Option) { intersperse_size_hint(&self.iter, self.started, self.next_item.is_some()) } fn fold(self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { let separator = self.separator; intersperse_fold( self.iter, init, f, move || separator.clone(), self.started, self.next_item, ) } } /// An iterator adapter that places a separator between all elements. /// /// This `struct` is created by [`Iterator::intersperse_with`]. See its /// documentation for more information. #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub struct IntersperseWith where I: Iterator, { started: bool, separator: G, next_item: Option, iter: Fuse, } #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] impl FusedIterator for IntersperseWith where I: FusedIterator, G: FnMut() -> I::Item, { } #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] impl fmt::Debug for IntersperseWith where I: Iterator + fmt::Debug, I::Item: fmt::Debug, G: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("IntersperseWith") .field("started", &self.started) .field("separator", &self.separator) .field("iter", &self.iter) .field("next_item", &self.next_item) .finish() } } #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] impl Clone for IntersperseWith where I: Iterator + Clone, I::Item: Clone, G: Clone, { fn clone(&self) -> Self { Self { started: self.started, separator: self.separator.clone(), iter: self.iter.clone(), next_item: self.next_item.clone(), } } } impl IntersperseWith where I: Iterator, G: FnMut() -> I::Item, { pub(in crate::iter) fn new(iter: I, separator: G) -> Self { Self { started: false, separator, next_item: None, iter: iter.fuse() } } } #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] impl Iterator for IntersperseWith where I: Iterator, G: FnMut() -> I::Item, { type Item = I::Item; #[inline] fn next(&mut self) -> Option { if self.started { if let Some(v) = self.next_item.take() { Some(v) } else { let next_item = self.iter.next(); if next_item.is_some() { self.next_item = next_item; Some((self.separator)()) } else { None } } } else { self.started = true; self.iter.next() } } fn size_hint(&self) -> (usize, Option) { intersperse_size_hint(&self.iter, self.started, self.next_item.is_some()) } fn fold(self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { intersperse_fold(self.iter, init, f, self.separator, self.started, self.next_item) } } fn intersperse_size_hint(iter: &I, started: bool, next_is_some: bool) -> (usize, Option) where I: Iterator, { let (lo, hi) = iter.size_hint(); ( lo.saturating_sub(!started as usize) .saturating_add(next_is_some as usize) .saturating_add(lo), hi.and_then(|hi| { hi.saturating_sub(!started as usize) .saturating_add(next_is_some as usize) .checked_add(hi) }), ) } fn intersperse_fold( mut iter: I, init: B, mut f: F, mut separator: G, started: bool, mut next_item: Option, ) -> B where I: Iterator, F: FnMut(B, I::Item) -> B, G: FnMut() -> I::Item, { let mut accum = init; let first = if started { next_item.take() } else { let n = iter.next(); // skip invoking fold() for empty iterators if n.is_none() { return accum; } n }; if let Some(x) = first { accum = f(accum, x); } iter.fold(accum, |mut accum, x| { accum = f(accum, separator()); accum = f(accum, x); accum }) }