use core::{num::NonZeroIsize, fmt::Debug, hint, convert::TryFrom};
use crate::{
storage::{ListStorage, MoveFix},
util::unreachable_debugchecked,
NodeValue,
};
#[derive(Copy, Clone, Debug, Hash)]
pub struct Node<B, L, K>
where
K: Clone + Debug + Eq,
{
pub(super) value: NodeData<B, L, K>,
pub(super) parent: Option<K>,
}
impl<B, L, K> Node<B, L, K>
where
K: Clone + Debug + Eq,
{
pub(crate) unsafe fn leaf(value: L, parent: Option<K>) -> Self {
Self {
value: NodeData::Leaf(value),
parent,
}
}
pub(crate) unsafe fn root(value: L) -> Self {
{
Self::leaf(value, None)
}
}
}
impl<B, L> MoveFix for Node<B, L, usize> {
unsafe fn fix_shift<S>(storage: &mut S, shifted_from: usize, shifted_by: NonZeroIsize)
where
S: ListStorage<Element = Self>,
{
let fix_starting_from = if shifted_by.get() > 0 {
shifted_from + 1 } else {
shifted_from
};
if fix_starting_from >= storage.len() {
return;
};
for i in fix_starting_from..storage.len() {
let old_index = isize::try_from(i)
.unwrap_or_else(|_| hint::unreachable_unchecked())
- shifted_by.get(); Self::fix_move(
storage,
usize::try_from(old_index).unwrap_or_else(|_| hint::unreachable_unchecked()),
i,
);
}
}
unsafe fn fix_move<S>(storage: &mut S, previous_index: usize, current_index: usize)
where
S: ListStorage<Element = Self>,
{
match {
&storage.get_unchecked(current_index).value
} {
NodeData::Branch { left_child, right_child, .. } => {
let (left_child, right_child) = (*left_child, *right_child);
let mut fix_child = |child| {
let child = {
storage.get_unchecked_mut(child)
};
child.parent = Some(current_index);
};
fix_child(left_child);
if let Some(right_child) = right_child {
fix_child(right_child);
}
},
NodeData::Leaf(..) => {},
}
let parent_index = if let Some(i) = {
storage.get_unchecked(current_index).parent
} {
i
} else {
return;
};
let parent = storage.get_unchecked_mut(parent_index);
let (left_child, right_child) = match &mut parent.value {
NodeData::Branch {
left_child,
right_child,
..
} => (left_child, right_child),
NodeData::Leaf(..) =>
{
unreachable_debugchecked("parent nodes cannot be leaves")
}
};
if *left_child == previous_index {
*left_child = current_index;
} else if *right_child == Some(previous_index) {
*right_child = Some(current_index);
} else {
{
unreachable_debugchecked(
"failed to identify whether the node is the left or right child",
)
}
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub(super) enum NodeData<B, L, K>
where
K: Clone + Debug + Eq,
{
Branch {
payload: B,
left_child: K,
right_child: Option<K>,
},
Leaf(L),
}
impl<B, L, K> NodeData<B, L, K>
where
K: Clone + Debug + Eq,
{
pub(super) fn as_ref(&self) -> NodeData<&B, &L, K> {
match self {
Self::Branch {
payload,
left_child,
right_child,
} => NodeData::Branch {
payload,
left_child: (*left_child).clone(),
right_child: (*right_child).clone(),
},
Self::Leaf(x) => NodeData::Leaf(x),
}
}
pub(super) fn as_mut(&mut self) -> NodeData<&mut B, &mut L, K> {
match self {
Self::Branch {
payload,
left_child,
right_child,
} => NodeData::Branch {
payload,
left_child: left_child.clone(),
right_child: right_child.clone(),
},
Self::Leaf(x) => NodeData::Leaf(x),
}
}
#[allow(clippy::missing_const_for_fn)] pub(super) fn into_value(self) -> NodeValue<B, L> {
match self {
Self::Branch { payload, .. } => NodeValue::Branch(payload),
Self::Leaf(x) => NodeValue::Leaf(x),
}
}
}