use std::rc::Rc; /// An iterator that allows to insert a given element `elem` every `interval` elements of the input /// iterator. /// /// The interleaved element is wrapped in a `Rc` smart pointer to avoid hard copies. pub struct Intersperse { inner: std::iter::Peekable, // required to have `peek(..)` elem: Rc, interval: u32, intersperse: u32, } impl Intersperse { pub fn new(inner: I, elem: I::Item, interval: u32) -> Intersperse { Intersperse { inner: inner.peekable(), elem: Rc::new(elem), interval: interval + 1, // `+ 1` needed to align semantics and implementation intersperse: 0, } } } impl Iterator for Intersperse { type Item = Rc; fn next(&mut self) -> Option { // Counter rotation self.intersperse = (self.intersperse + 1) % self.interval; // Insert a copy of the element only when counter goes to 0 and we haven't reached the end // of the inner iterator. if self.intersperse == 0 && self.inner.peek().is_some() { Some(Rc::clone(&self.elem)) } else { self.inner.next() .map(|x| Rc::new(x)) // Go from Option to Option> } } } /// Extend `Iterator`s with `intersperse` function. pub trait IntersperseIterator: Iterator { fn intersperse(self, elem: Self::Item, interval: u32) -> Intersperse where Self: Sized, { Intersperse::new(self, elem, interval) } } impl IntersperseIterator for I {}