use super::{AANode, Node};
use core::fmt::{self, Debug, Display, Formatter};
#[derive(Debug)]
pub enum TraverseStep<R> {
Left,
Right,
Value(Option<R>)
}
impl<T> AANode<T> {
pub fn traverse<'a, F, G, R>(&'a self, down_callback: F, up_callback: G) -> Option<R>
where
F: Fn(&'a T) -> TraverseStep<R> + Copy,
G: Fn(&'a T, Option<R>) -> Option<R> + Copy
{
self.as_ref().and_then(
|Node {
content,
left_child,
right_child,
..
}| {
let child = match down_callback(content) {
TraverseStep::Left => left_child,
TraverseStep::Right => right_child,
TraverseStep::Value(v) => return v
};
up_callback(content, child.traverse(down_callback, up_callback))
}
)
}
}
pub(crate) struct TraverseMutError(&'static str);
impl Display for TraverseMutError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Attempt to turn {} but there is no such child", self.0)
}
}
impl Debug for TraverseMutError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(self, f)
}
}
pub(crate) struct TraverseMut<'a, T> {
node: &'a mut AANode<T>
}
#[allow(dead_code)] impl<'a, T> TraverseMut<'a, T> {
pub(crate) fn is_leaf(&self) -> bool {
self.node.is_leaf()
}
pub(crate) fn peek(&self) -> &T {
&self
.node
.as_ref()
.expect("This node should not be nil")
.content
}
pub(crate) fn into_content(self) -> &'a mut T {
&mut self
.node
.as_mut()
.expect("This node should not be nil")
.content
}
pub(crate) fn has_left_child(&self) -> bool {
self.node
.as_ref()
.map(|node| !node.left_child.is_nil())
.unwrap_or(false)
}
pub(crate) fn peek_left_child(&self) -> Option<&T> {
self.node
.as_ref()
.and_then(|node| node.left_child.as_ref().map(|left| &left.content))
}
pub(crate) fn turn_left(self) -> Result<Self, TraverseMutError> {
Ok(Self {
node: self
.node
.as_mut()
.and_then(|node| {
(!node.left_child.is_nil()).then(|| &mut node.left_child)
})
.ok_or(TraverseMutError("left"))?
})
}
pub(crate) fn has_right_child(&self) -> bool {
self.node
.as_ref()
.map(|node| !node.right_child.is_nil())
.unwrap_or(false)
}
pub(crate) fn peek_right_child(&self) -> Option<&T> {
self.node
.as_ref()
.and_then(|node| node.right_child.as_ref().map(|left| &left.content))
}
pub(crate) fn turn_right(self) -> Result<Self, TraverseMutError> {
Ok(Self {
node: self
.node
.as_mut()
.and_then(|node| {
(!node.right_child.is_nil()).then(|| &mut node.right_child)
})
.ok_or(TraverseMutError("right"))?
})
}
}
impl<T> AANode<T> {
pub(crate) fn traverse_mut(&mut self) -> Option<TraverseMut<'_, T>> {
(!self.is_nil()).then(|| TraverseMut { node: self })
}
}