Search code examples
rustiterator

How to implement `Iterator` for a resizing array stack using `NonNull`?


I am following the guide to implement a resizing array stack using NonNull:

pub struct ResizingStack<T> {
    a: NonNull<T>,
    n: usize,
    capacity: usize,
}

Now the basic functionalities (e.g., push and pop) work well. The complete code can be found here. But I have some troubles in implementing the Iterator trait.

For a forward iterator, a simple solution is to make ResizingStack coerce to, and behave like, a slice.

impl<T> Deref for Vec<T> {
    type Target = [T];
    fn deref(&self) -> &[T] {
        unsafe {
            std::slice::from_raw_parts(self.a.as_ptr(), self.n)
        }
    }
}

However, a stack, in fact, should have a backward iterator. The followings are my attempts:

pub struct StackIter<'a, T> {
    buf: &'a ResizingStack<T>,
    index: usize,
}

impl<T> ResizingStack<T> {
    pub fn iter(&self) -> StackIter<'_, T> {
        StackIter {
            buf: self,
            index: self.n,
        }
    }
}

impl<'a, T> Iterator for StackIter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        if self.index == 0 {
            None
        } else {
            let item;
            unsafe {
                item = Some(ptr::read(self.buf.a.as_ptr().add(self.index - 1)));
                self.index -= 1;
            }
            item // ERROR: expected `Option<&T>`, but found `Option<T>`.
        }
    }
}

Solution

  • There's no need to use unsafe code for an iterator that yields &T.

    Here's a solution that uses .split_last():

    pub struct StackIter<'a, T> {
        buf: &'a [T],
    }
    
    impl<'a, T> Iterator for StackIter<'a, T> {
        type Item = &'a T;
    
        fn next(&mut self) -> Option<Self::Item> {
            let (last, remainder) = self.buf.split_last()?;
            self.buf = remainder;
            Some(last)
        }
    }
    

    Alternatively, here's a solution that wraps .rev():

    use std::{iter::Rev, slice};
    
    pub struct StackIter<'a, T> {
        inner: Rev<slice::Iter<'a, T>>,
    }
    
    impl<'a, T> Iterator for StackIter<'a, T> {
        type Item = &'a T;
    
        fn next(&mut self) -> Option<Self::Item> {
            self.inner.next()
        }
    }
    

    At this point, we may as well ditch the wrapper and return the adapter directly:

    impl<T> ResizingStack<T> {
        pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a T> {
            self.deref().iter().rev()
        }
    }