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>`.
}
}
}
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()
}
}