use crate::linked_list::{LinkedList, LinkedListIndex, LinkedListItem};
pub trait Walker<Context> {
type Item;
fn walk_next(&mut self, context: Context) -> Option<Self::Item>;
fn iter(self, context: Context) -> WalkerIter<Self, Context>
where
Self: Sized,
Context: Clone,
{
WalkerIter {
walker: self,
context,
}
}
}
#[derive(Clone, Debug)]
pub struct WalkerIter<W, C> {
walker: W,
context: C,
}
impl<W, C> WalkerIter<W, C>
where
W: Walker<C>,
C: Clone,
{
pub fn context(&self) -> C {
self.context.clone()
}
pub fn inner_ref(&self) -> &W {
&self.walker
}
pub fn inner_mut(&mut self) -> &mut W {
&mut self.walker
}
}
impl<W, C> Iterator for WalkerIter<W, C>
where
W: Walker<C>,
C: Clone,
{
type Item = W::Item;
fn next(&mut self) -> Option<Self::Item> {
self.walker.walk_next(self.context.clone())
}
}
impl<'a, C, W: ?Sized> Walker<C> for &'a mut W
where
W: Walker<C>,
{
type Item = W::Item;
fn walk_next(&mut self, context: C) -> Option<Self::Item> {
(**self).walk_next(context)
}
}
pub struct LinkedListWalker {
current: Option<LinkedListIndex>,
reverse: bool,
}
impl LinkedListWalker {
pub fn new<T>(list: &LinkedList<T>, start: LinkedListIndex, reverse: bool) -> Self {
Self {
current: Some(start),
reverse: reverse,
}
}
}
impl<T> Walker<&LinkedList<T>> for LinkedListWalker {
type Item = LinkedListIndex;
fn walk_next(&mut self, context: &LinkedList<T>) -> Option<Self::Item> {
if let Some(current) = self.current {
return if self.reverse {
context.get(current).and_then(|item| {
self.current = item.prev_index;
item.prev_index
})
} else {
context.get(current).and_then(|item| {
self.current = item.next_index;
item.next_index
})
};
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn test_list_walker() {
let mut list = LinkedList::new();
list.extend(0..=100);
let mut count = 0;
let mut walker = LinkedListWalker::new(&list, list.tail.unwrap(), true);
assert_eq!(list.get(list.head.unwrap()).unwrap().value, 0);
assert_eq!(list.get(list.tail.unwrap()).unwrap().value, 100);
list.tail_mut().unwrap().value = 0;
while let Some(index) = walker.walk_next(&list) {
count += 1;
list.get_mut(index).unwrap().value = count;
}
assert_eq!(count, 100);
assert_eq!(list.get(list.head.unwrap()).unwrap().value, 100);
assert_eq!(list.get(list.tail.unwrap()).unwrap().value, 0);
}
}