use std::num::NonZeroU128;
pub const TEMPLATE_SLOT_PATH_MAX_PATH_BITS: usize = u128::BITS as usize - 1;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TemplatePath {
path: u128,
}
impl TemplatePath {
pub(crate) const fn empty() -> Self {
Self { path: 0 }
}
pub(crate) const fn from_bits(path: u128) -> Self {
Self { path }
}
pub(crate) const fn root(index: usize) -> Self {
debug_assert!(
index < u128::BITS as usize,
"template root index exceeds path bit width"
);
Self {
path: 1u128 << index,
}
}
pub(crate) const fn bits(self) -> u128 {
self.path
}
pub const fn next_child(self) -> Self {
Self {
path: (self.path << 1) | 1,
}
}
pub const fn next_sibling(self) -> Self {
Self {
path: self.path << 1,
}
}
pub const fn split_insertion(self) -> (TemplatePath, usize) {
if self.path == 0 {
return (TemplatePath::from_bits(0), 0);
}
let insertion_index = self.path.trailing_zeros() as usize;
let parent = (self.path >> insertion_index) >> 1;
(TemplatePath::from_bits(parent), insertion_index)
}
pub const fn is_root(self) -> bool {
self.depth() == 1
}
pub const fn depth(self) -> usize {
self.path.count_ones() as usize
}
pub const fn is_empty(self) -> bool {
self.path == 0
}
pub fn segments(self) -> TemplatePathSegments {
TemplatePathSegments { path: self.path }
}
pub fn starts_with(self, ancestor: TemplatePath) -> bool {
let ancestor_depth = ancestor.depth();
if ancestor_depth == 0 {
return true;
}
if ancestor_depth > self.depth() {
return false;
}
if ancestor_depth == self.depth() {
return self.path == ancestor.path;
}
let self_bits = self.bit_len();
let ancestor_bits = ancestor.bit_len();
if ancestor_bits > self_bits {
return false;
}
let suffix_bits = self_bits - ancestor_bits;
suffix_bits > 0
&& (self.path >> suffix_bits) == ancestor.path
&& ((self.path >> (suffix_bits - 1)) & 1) == 1
}
pub(crate) fn bit_len(self) -> u32 {
u128::BITS - self.path.leading_zeros()
}
}
#[derive(Clone, Copy)]
pub struct TemplatePathSegments {
path: u128,
}
impl Iterator for TemplatePathSegments {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
let bit_len = u128::BITS - self.path.leading_zeros();
if bit_len == 0 {
return None;
}
let marker = 1u128 << (bit_len - 1);
let remaining_path = self.path ^ marker;
let next_marker_bit_len = u128::BITS - remaining_path.leading_zeros();
let segment = if next_marker_bit_len == 0 {
bit_len - 1
} else {
bit_len - next_marker_bit_len - 1
};
self.path = remaining_path;
Some(segment as usize)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
impl ExactSizeIterator for TemplatePathSegments {
fn len(&self) -> usize {
self.path.count_ones() as usize
}
}
#[cfg(feature = "serialize")]
impl serde::Serialize for TemplatePath {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serde::Serialize::serialize(&self.path, serializer)
}
}
#[cfg(feature = "serialize")]
impl<'de> serde::Deserialize<'de> for TemplatePath {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let path = <u128 as serde::Deserialize>::deserialize(deserializer)?;
Ok(Self { path })
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub struct TemplateSlotPath(NonZeroU128);
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct TemplateSlotTarget {
static_path: TemplatePath,
is_last_static_node: bool,
}
impl TemplateSlotTarget {
pub const fn static_path(self) -> TemplatePath {
self.static_path
}
pub const fn is_last_static_node(self) -> bool {
self.is_last_static_node
}
}
impl TemplateSlotPath {
const TARGET_LAST_STATIC_NODE: u128 = 1;
const MAX_PAYLOAD: u128 = u128::MAX >> (u128::BITS as usize - TEMPLATE_SLOT_PATH_MAX_PATH_BITS);
const fn new(bits: u128) -> Self {
match NonZeroU128::new(bits) {
Some(bits) => Self(bits),
None => panic!("bad slot path"),
}
}
const fn encode_payload(path: TemplatePath) -> u128 {
let payload = path.bits();
if payload > Self::MAX_PAYLOAD {
panic!("slot path overflow");
}
payload << 1
}
pub(crate) const fn static_node(path: TemplatePath) -> Self {
if path.is_empty() {
panic!("bad slot target");
}
Self::new(Self::encode_payload(path))
}
pub(crate) const fn last_static_node(path: TemplatePath) -> Self {
Self::new(Self::encode_payload(path) | Self::TARGET_LAST_STATIC_NODE)
}
pub(crate) const fn bits(self) -> u128 {
self.0.get()
}
pub(crate) const fn target(self) -> TemplateSlotTarget {
let bits = self.bits();
TemplateSlotTarget {
static_path: TemplatePath::from_bits(bits >> 1),
is_last_static_node: bits & Self::TARGET_LAST_STATIC_NODE
== Self::TARGET_LAST_STATIC_NODE,
}
}
pub(crate) const fn static_path(self) -> TemplatePath {
self.target().static_path()
}
pub(crate) const fn is_last_static_node(self) -> bool {
self.target().is_last_static_node()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn slot_path_payload_uses_all_but_the_tag_bit() {
assert_eq!(TEMPLATE_SLOT_PATH_MAX_PATH_BITS, 127);
assert_eq!(TemplateSlotPath::MAX_PAYLOAD, u128::MAX >> 1);
}
#[test]
fn root_paths_are_single_marker_bits() {
assert_eq!(TemplatePath::root(0).bits(), 0b1);
assert_eq!(TemplatePath::root(1).bits(), 0b10);
assert_eq!(TemplatePath::root(3).bits(), 0b1000);
assert_eq!(TemplatePath::root(127).bits(), 1u128 << 127);
}
#[test]
fn depth_counts_path_segments() {
assert_eq!(TemplatePath::empty().depth(), 0);
assert_eq!(TemplatePath::from_bits(0b1).depth(), 1);
assert_eq!(TemplatePath::from_bits(0b100101).depth(), 3);
}
#[test]
fn segments_reads_sibling_indexes() {
let path = TemplatePath::root(2)
.next_child()
.next_sibling()
.next_child();
assert_eq!(path.bits(), 0b100101);
assert_eq!(path.segments().collect::<Vec<_>>(), vec![2, 1, 0]);
}
#[test]
fn segments_stop_at_end() {
let mut segments = TemplatePath::root(0).segments();
assert_eq!(segments.next(), Some(0));
assert_eq!(segments.next(), None);
}
#[test]
fn starts_with_matches_segment_prefixes() {
let root_zero = TemplatePath::root(0);
let root_one = TemplatePath::root(1);
let root_zero_child_one = root_zero.next_child().next_sibling();
let root_one_child_zero = root_one.next_child();
assert!(root_zero.starts_with(TemplatePath::empty()));
assert!(root_zero.starts_with(root_zero));
assert!(root_zero_child_one.starts_with(root_zero));
assert!(root_one_child_zero.starts_with(root_one));
assert!(!root_one.starts_with(root_zero));
assert!(!root_one_child_zero.starts_with(root_zero));
assert!(!root_zero.starts_with(root_zero_child_one));
}
#[test]
fn starts_with_rejects_raw_bit_prefixes_across_segment_boundaries() {
assert!(!TemplatePath::from_bits(0b10).starts_with(TemplatePath::from_bits(0b1)));
assert!(!TemplatePath::from_bits(0b101).starts_with(TemplatePath::from_bits(0b1)));
assert!(!TemplatePath::from_bits(0b1001).starts_with(TemplatePath::from_bits(0b10)));
assert!(
!TemplatePath::root(0)
.next_child()
.starts_with(TemplatePath::root(5))
);
assert!(TemplatePath::from_bits(0b110).starts_with(TemplatePath::from_bits(0b1)));
assert!(TemplatePath::from_bits(0b101).starts_with(TemplatePath::from_bits(0b10)));
}
#[test]
fn split_insertion_returns_parent_and_sibling_index() {
let path = TemplatePath::root(1)
.next_child()
.next_sibling()
.next_sibling();
let (parent, index) = path.split_insertion();
assert_eq!(path.bits(), 0b10100);
assert_eq!(parent.bits(), TemplatePath::root(1).bits());
assert_eq!(index, 2);
}
#[test]
fn slot_path_tag_marks_last_static_node() {
let path = TemplatePath::root(0).next_child().next_sibling();
let static_node = TemplateSlotPath::static_node(path);
let last_static_node = TemplateSlotPath::last_static_node(path);
assert_eq!(static_node.static_path().bits(), path.bits());
assert!(!static_node.is_last_static_node());
assert_eq!(last_static_node.static_path().bits(), path.bits());
assert!(last_static_node.is_last_static_node());
}
}