use crate::domain::{BoundingBox, Cut};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct NodeRef(u32);
impl NodeRef {
pub(crate) const LEAF_BIT: u32 = 1 << 31;
pub(crate) const INDEX_MASK: u32 = !Self::LEAF_BIT;
pub const MAX_INDEX: u32 = Self::INDEX_MASK;
#[must_use]
pub(crate) fn internal(idx: u32) -> Self {
debug_assert!(idx <= Self::MAX_INDEX, "internal index overflow");
Self(idx)
}
#[must_use]
pub(crate) fn leaf(idx: u32) -> Self {
debug_assert!(idx <= Self::MAX_INDEX, "leaf index overflow");
Self(idx | Self::LEAF_BIT)
}
#[must_use]
#[inline]
pub fn is_leaf(self) -> bool {
self.0 & Self::LEAF_BIT != 0
}
#[must_use]
#[inline]
pub fn is_internal(self) -> bool {
!self.is_leaf()
}
#[must_use]
#[inline]
pub fn index(self) -> usize {
(self.0 & Self::INDEX_MASK) as usize
}
#[must_use]
#[inline]
pub(crate) fn raw(self) -> u32 {
self.0
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct InternalData<const D: usize> {
pub cut: Cut,
pub bbox: BoundingBox<D>,
pub left: NodeRef,
pub right: NodeRef,
pub parent: Option<NodeRef>,
pub mass: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LeafData {
pub point_idx: usize,
pub parent: Option<NodeRef>,
pub mass: u64,
}
#[derive(Debug)]
pub enum NodeView<'a, const D: usize> {
Internal(&'a InternalData<D>),
Leaf(&'a LeafData),
}
impl<const D: usize> NodeView<'_, D> {
#[must_use]
#[inline]
pub fn mass(&self) -> u64 {
match self {
Self::Internal(i) => i.mass,
Self::Leaf(l) => l.mass,
}
}
#[must_use]
#[inline]
pub fn parent(&self) -> Option<NodeRef> {
match self {
Self::Internal(i) => i.parent,
Self::Leaf(l) => l.parent,
}
}
#[must_use]
#[inline]
pub fn is_internal(&self) -> bool {
matches!(self, Self::Internal(_))
}
#[must_use]
#[inline]
pub fn is_leaf(&self) -> bool {
matches!(self, Self::Leaf(_))
}
}
#[derive(Debug)]
pub enum NodeViewMut<'a, const D: usize> {
Internal(&'a mut InternalData<D>),
Leaf(&'a mut LeafData),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ref_internal_round_trip() {
let r = NodeRef::internal(42);
assert!(r.is_internal());
assert!(!r.is_leaf());
assert_eq!(r.index(), 42);
}
#[test]
fn ref_leaf_round_trip() {
let r = NodeRef::leaf(7);
assert!(r.is_leaf());
assert!(!r.is_internal());
assert_eq!(r.index(), 7);
}
#[test]
fn ref_internal_and_leaf_with_same_index_differ() {
let i = NodeRef::internal(0);
let l = NodeRef::leaf(0);
assert_ne!(i, l);
assert_eq!(i.index(), l.index());
}
#[test]
fn ref_max_index_round_trips() {
let r = NodeRef::internal(NodeRef::MAX_INDEX);
assert_eq!(r.index(), NodeRef::MAX_INDEX as usize);
assert!(r.is_internal());
}
#[test]
fn leaf_view_mass_and_parent() {
let data = LeafData {
point_idx: 0,
parent: Some(NodeRef::internal(5)),
mass: 3,
};
let view: NodeView<'_, 2> = NodeView::Leaf(&data);
assert_eq!(view.mass(), 3);
assert!(view.is_leaf());
assert!(!view.is_internal());
assert_eq!(view.parent(), Some(NodeRef::internal(5)));
}
}