use crate::{
Node,
node::{Child, child_storage::Storage},
};
impl<T, C> Node<T, C>
where
C: Storage + ?Sized,
{
#[inline]
pub fn descendants(
&self,
include_self: bool,
) -> impl Iterator<Item = (heapless::Vec<u8, 16>, Child<&Self, &T>)> {
DescendantIter::new(self, include_self)
}
#[inline]
pub fn descendant_nodes(
&self,
include_self: bool,
) -> impl Iterator<Item = (heapless::Vec<u8, 16>, &Self)> {
DescendantIter::new(self, include_self).filter_map(|(addr, child)| match child {
Child::Path(node) => Some((addr, node)),
_ => None,
})
}
}
struct DescendantIter<'a, T, C>
where
C: Storage + ?Sized,
{
node_path: heapless::Vec<(u8, &'a Node<T, C>), 16>,
next_child: u8,
yield_self: bool,
}
impl<'a, T, C> DescendantIter<'a, T, C>
where
C: Storage + ?Sized,
{
#[inline]
fn new(node: &'a Node<T, C>, include_self: bool) -> Self {
Self {
node_path: heapless::Vec::from_iter([(0, node)]),
next_child: 0,
yield_self: include_self,
}
}
}
impl<'a, T, C> Iterator for DescendantIter<'a, T, C>
where
C: Storage + ?Sized,
{
type Item = (heapless::Vec<u8, 16>, Child<&'a Node<T, C>, &'a T>);
fn next(&mut self) -> Option<Self::Item> {
if self.yield_self {
self.yield_self = false;
return Some((
heapless::Vec::new(),
Child::Path(self.node_path.first().unwrap().1),
));
}
while let Some(&(this_addr, node)) = self.node_path.last() {
let ret = match node
.children
.iter()
.find(|&(addr, _)| addr >= self.next_child)
{
Some((addr, child)) => {
let mut path = self
.node_path
.iter()
.map(|&(addr, _node)| addr)
.skip(1) .collect::<heapless::Vec<u8, 16>>();
path.push(addr).unwrap();
if let Child::Path(node) = child {
self.node_path
.push((addr, C::as_ref(node)))
.map_err(|_| ())
.unwrap();
self.next_child = 0;
return Some((path, child.as_ref().map_node(C::as_ref)));
}
self.next_child = addr;
Some((path, child.as_ref().map_node(C::as_ref)))
}
None => {
self.node_path.pop();
self.next_child = this_addr;
None
}
};
while self.next_child == 255 {
let Some((popped, _)) = self.node_path.pop() else {
break;
};
self.next_child = popped;
}
self.next_child += 1;
if ret.is_some() {
return ret;
}
}
None
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::node::StrideOpsExt;
#[test]
fn zero() {
assert_eq!(0, Node::<()>::EMPTY.descendants(false).count());
assert_eq!(0, Node::<()>::EMPTY.descendant_nodes(false).count());
assert_eq!(1, Node::<()>::EMPTY.descendants(true).count());
assert_eq!(1, Node::<()>::EMPTY.descendant_nodes(true).count());
}
#[test]
fn single_level() {
let node = Node::<()>::EMPTY
.with_child(0, Child::Fringe(()))
.with_child(1, Child::Fringe(()))
.with_child(255, Child::Fringe(()));
assert_eq!(3, node.descendants(false).count());
let node = node.with_child(
3,
Child::Leaf {
prefix: Default::default(),
value: Default::default(),
},
);
assert_eq!(4, node.descendants(false).count());
assert_eq!(0, node.descendant_nodes(false).count());
node.descendants(false)
.zip([0, 1, 3, 255])
.for_each(|((path, child), addr)| {
assert_eq!(&path, &[addr]);
match child {
Child::Leaf { .. } | Child::Fringe(..) => {}
Child::Path(..) => panic!(),
}
});
}
#[test]
fn multi_level() {
let node = Node::<()>::EMPTY
.with_child(0, Child::dummy_leaf())
.with_child(
2,
Node::EMPTY
.with_child(12, Child::dummy_leaf())
.with_child(32, Child::dummy_fringe())
.into_child(),
)
.with_child(5, Child::dummy_leaf())
.with_child(
255,
Node::EMPTY
.with_child(0, Child::dummy_fringe())
.with_child(1, Child::dummy_fringe())
.with_child(255, Node::EMPTY.into_child())
.into_child(),
);
assert_eq!(9, node.descendants(false).count());
assert_eq!(10, node.descendants(true).count());
assert_eq!(3, node.descendant_nodes(false).count());
assert_eq!(4, node.descendant_nodes(true).count());
for ((path, _child), expected_path) in node.descendants(false).zip([
&[0u8] as &[u8],
&[2],
&[2, 12],
&[2, 32],
&[5],
&[255],
&[255, 0],
&[255, 1],
&[255, 255],
]) {
assert_eq!(&path, expected_path);
}
for ((path, _child), expected_path) in
node.descendant_nodes(false)
.zip([&[2u8] as &[u8], &[255], &[255, 255]])
{
assert_eq!(&path, expected_path);
}
}
}