Search code examples
rustiterator

Rust: Iterator that repeats the first and last element of another Iterator?


Is there an Iterator, either in std or a maintained crate, that repeats the first and last element of another Iterator given Item is Clone?

Example:

let iter = [1, 2, 3].into_iter();

assert!(iter.repeat_first_and_last().eq([1, 1, 2, 3, 3]));

Solution

  • I ended up rolling my own.

    use std::{mem::take, iter::Fuse};
    
    use tap::Tap;
    
    struct Padded<T: Iterator> {
        inner: Fuse<T>,
        repeat_first: bool,
        repeat_last: bool,
        next: Option<T::Item>,
    }
    
    impl<T: Iterator> Padded<T>
    where
        T::Item: Clone,
    {
        fn new(inner: impl IntoIterator<IntoIter = T>) -> Self
        where
            T::Item: Clone,
        {
            let mut inner = inner.into_iter().fuse();
            let next = inner.next();
            
            Self { inner, next, repeat_first: true, repeat_last: true, }
        }
    }
    
    impl<T: Iterator> Iterator for Padded<T>
    where
        T::Item: Clone,
    {
        type Item = T::Item;
    
        fn next(&mut self) -> Option<Self::Item> {
            self.next.take().tap(|next| {
                if take(&mut self.repeat_first) {
                    self.next = next.clone();
                } else {
                    self.next = self.inner.next().or_else(|| {
                        next.as_ref().filter(|_| take(&mut self.repeat_last)).cloned()
                    })
                }
            })
        }
    }
    
    fn main() {
        Padded::new([1, 2, 3]).for_each(|n| print!("{n}"));
    }