pub const MAX_PREFIX_LEN: usize = 10;
#[derive(Debug, Clone)]
pub struct NodeHeader {
pub num_children: u16,
pub prefix_len: u32,
pub prefix: [u8; MAX_PREFIX_LEN],
pub values: Vec<RowId>,
}
impl Default for NodeHeader {
fn default() -> Self {
Self {
num_children: 0,
prefix_len: 0,
prefix: [0u8; MAX_PREFIX_LEN],
values: Vec::new(),
}
}
}
#[allow(clippy::indexing_slicing)] impl NodeHeader {
pub fn with_prefix(prefix: &[u8]) -> Self {
let mut header = Self::default();
header.set_prefix(prefix);
header
}
pub fn set_prefix(&mut self, prefix: &[u8]) {
let len = prefix.len().min(MAX_PREFIX_LEN);
self.prefix_len = prefix.len() as u32;
self.prefix[..len].copy_from_slice(&prefix[..len]);
}
pub fn get_prefix(&self) -> &[u8] {
let len = (self.prefix_len as usize).min(MAX_PREFIX_LEN);
&self.prefix[..len]
}
}
pub type RowId = u64;
#[derive(Debug, Clone)]
pub enum ArtNode {
Node4(Box<Node4>),
Node16(Box<Node16>),
Node48(Box<Node48>),
Node256(Box<Node256>),
Leaf(LeafNode),
}
#[derive(Debug, Clone)]
pub struct LeafNode {
pub key: Vec<u8>,
primary: RowId,
extra: Vec<RowId>,
}
impl LeafNode {
pub fn new(key: Vec<u8>, value: RowId) -> Self {
Self { key, primary: value, extra: Vec::new() }
}
pub fn from_values(key: Vec<u8>, primary: RowId, extra: Vec<RowId>) -> Self {
Self { key, primary, extra }
}
pub fn value(&self) -> RowId {
self.primary
}
pub fn values_count(&self) -> usize {
1 + self.extra.len()
}
pub fn push_value(&mut self, value: RowId) {
self.extra.push(value);
}
pub fn values_iter(&self) -> impl Iterator<Item = RowId> + '_ {
std::iter::once(self.primary).chain(self.extra.iter().copied())
}
pub fn all_values(&self) -> Vec<RowId> {
let mut v = Vec::with_capacity(1 + self.extra.len());
v.push(self.primary);
v.extend_from_slice(&self.extra);
v
}
pub fn take_values(&mut self) -> (RowId, Vec<RowId>) {
let primary = self.primary;
self.primary = 0;
(primary, std::mem::take(&mut self.extra))
}
pub fn remove_value(&mut self, row_id: RowId) -> (bool, bool) {
if self.primary == row_id {
if let Some(replacement) = self.extra.pop() {
self.primary = replacement;
return (true, false);
}
return (true, true); }
if let Some(pos) = self.extra.iter().position(|&v| v == row_id) {
self.extra.swap_remove(pos);
return (true, false);
}
(false, false)
}
pub fn matches(&self, key: &[u8]) -> bool {
self.key == key
}
}
#[derive(Debug, Clone)]
pub struct Node4 {
pub header: NodeHeader,
pub keys: [u8; 4],
pub children: [Option<ArtNode>; 4],
}
impl Default for Node4 {
fn default() -> Self {
Self {
header: NodeHeader::default(),
keys: [0u8; 4],
children: [None, None, None, None],
}
}
}
#[allow(clippy::indexing_slicing)] impl Node4 {
pub fn new() -> Self {
Self::default()
}
pub fn with_prefix(prefix: &[u8]) -> Self {
Self {
header: NodeHeader::with_prefix(prefix),
..Self::default()
}
}
pub fn is_full(&self) -> bool {
self.header.num_children >= 4
}
pub fn find_child_index(&self, key: u8) -> Option<usize> {
let n = self.header.num_children as usize;
for i in 0..n {
if self.keys[i] == key {
return Some(i);
}
}
None
}
pub fn get_child(&self, key: u8) -> Option<&ArtNode> {
self.find_child_index(key)
.and_then(|i| self.children[i].as_ref())
}
pub fn get_child_mut(&mut self, key: u8) -> Option<&mut ArtNode> {
self.find_child_index(key)
.and_then(|i| self.children[i].as_mut())
}
pub fn add_child(&mut self, key: u8, child: ArtNode) -> bool {
if self.is_full() {
return false;
}
let idx = self.header.num_children as usize;
self.keys[idx] = key;
self.children[idx] = Some(child);
self.header.num_children += 1;
true
}
pub fn remove_child(&mut self, key: u8) -> Option<ArtNode> {
if let Some(idx) = self.find_child_index(key) {
let child = self.children[idx].take();
let last_idx = (self.header.num_children - 1) as usize;
if idx != last_idx {
self.keys[idx] = self.keys[last_idx];
self.children[idx] = self.children[last_idx].take();
}
self.header.num_children -= 1;
child
} else {
None
}
}
pub fn grow(self) -> Node16 {
let mut node16 = Node16::with_prefix(self.header.get_prefix());
node16.header.prefix_len = self.header.prefix_len;
for i in 0..4 {
if let Some(child) = self.children[i].clone() {
node16.keys[i] = self.keys[i];
node16.children[i] = Some(child);
}
}
node16.header.num_children = self.header.num_children;
node16
}
pub fn iter_children(&self) -> impl Iterator<Item = (u8, &ArtNode)> {
let n = self.header.num_children as usize;
(0..n).filter_map(move |i| {
self.children[i].as_ref().map(|c| (self.keys[i], c))
})
}
}
#[derive(Debug, Clone)]
pub struct Node16 {
pub header: NodeHeader,
pub keys: [u8; 16],
pub children: [Option<ArtNode>; 16],
}
impl Default for Node16 {
fn default() -> Self {
Self {
header: NodeHeader::default(),
keys: [0u8; 16],
children: std::array::from_fn(|_| None),
}
}
}
#[allow(clippy::indexing_slicing)] impl Node16 {
pub fn new() -> Self {
Self::default()
}
pub fn with_prefix(prefix: &[u8]) -> Self {
Self {
header: NodeHeader::with_prefix(prefix),
..Self::default()
}
}
pub fn is_full(&self) -> bool {
self.header.num_children >= 16
}
pub fn should_shrink(&self) -> bool {
self.header.num_children <= 4
}
pub fn find_child_index(&self, key: u8) -> Option<usize> {
let n = self.header.num_children as usize;
for i in 0..n {
if self.keys[i] == key {
return Some(i);
}
}
None
}
pub fn get_child(&self, key: u8) -> Option<&ArtNode> {
self.find_child_index(key)
.and_then(|i| self.children[i].as_ref())
}
pub fn get_child_mut(&mut self, key: u8) -> Option<&mut ArtNode> {
self.find_child_index(key)
.and_then(|i| self.children[i].as_mut())
}
pub fn add_child(&mut self, key: u8, child: ArtNode) -> bool {
if self.is_full() {
return false;
}
let idx = self.header.num_children as usize;
self.keys[idx] = key;
self.children[idx] = Some(child);
self.header.num_children += 1;
true
}
pub fn remove_child(&mut self, key: u8) -> Option<ArtNode> {
if let Some(idx) = self.find_child_index(key) {
let child = self.children[idx].take();
let last_idx = (self.header.num_children - 1) as usize;
if idx != last_idx {
self.keys[idx] = self.keys[last_idx];
self.children[idx] = self.children[last_idx].take();
}
self.header.num_children -= 1;
child
} else {
None
}
}
pub fn grow(self) -> Node48 {
let mut node48 = Node48::with_prefix(self.header.get_prefix());
node48.header.prefix_len = self.header.prefix_len;
for i in 0..16 {
if let Some(child) = self.children[i].clone() {
let key = self.keys[i];
node48.child_index[key as usize] = i as u8;
node48.children[i] = Some(child);
}
}
node48.header.num_children = self.header.num_children;
node48
}
pub fn shrink(self) -> Node4 {
let mut node4 = Node4::with_prefix(self.header.get_prefix());
node4.header.prefix_len = self.header.prefix_len;
let mut idx = 0;
for i in 0..16 {
if let Some(child) = self.children[i].clone() {
node4.keys[idx] = self.keys[i];
node4.children[idx] = Some(child);
idx += 1;
if idx >= 4 {
break;
}
}
}
node4.header.num_children = idx as u16;
node4
}
pub fn iter_children(&self) -> impl Iterator<Item = (u8, &ArtNode)> {
let n = self.header.num_children as usize;
(0..n).filter_map(move |i| {
self.children[i].as_ref().map(|c| (self.keys[i], c))
})
}
}
#[derive(Debug, Clone)]
pub struct Node48 {
pub header: NodeHeader,
pub child_index: [u8; 256],
pub children: [Option<ArtNode>; 48],
}
impl Default for Node48 {
fn default() -> Self {
Self {
header: NodeHeader::default(),
child_index: [255u8; 256],
children: std::array::from_fn(|_| None),
}
}
}
#[allow(clippy::indexing_slicing)] impl Node48 {
pub fn new() -> Self {
Self::default()
}
pub fn with_prefix(prefix: &[u8]) -> Self {
Self {
header: NodeHeader::with_prefix(prefix),
..Self::default()
}
}
pub fn is_full(&self) -> bool {
self.header.num_children >= 48
}
pub fn should_shrink(&self) -> bool {
self.header.num_children <= 16
}
pub fn get_child(&self, key: u8) -> Option<&ArtNode> {
let idx = self.child_index[key as usize];
if idx != 255 {
self.children[idx as usize].as_ref()
} else {
None
}
}
pub fn get_child_mut(&mut self, key: u8) -> Option<&mut ArtNode> {
let idx = self.child_index[key as usize];
if idx != 255 {
self.children[idx as usize].as_mut()
} else {
None
}
}
fn find_free_slot(&self) -> Option<usize> {
for i in 0..48 {
if self.children[i].is_none() {
return Some(i);
}
}
None
}
pub fn add_child(&mut self, key: u8, child: ArtNode) -> bool {
if self.is_full() {
return false;
}
if let Some(slot) = self.find_free_slot() {
self.child_index[key as usize] = slot as u8;
self.children[slot] = Some(child);
self.header.num_children += 1;
true
} else {
false
}
}
pub fn remove_child(&mut self, key: u8) -> Option<ArtNode> {
let idx = self.child_index[key as usize];
if idx != 255 {
self.child_index[key as usize] = 255;
self.header.num_children -= 1;
self.children[idx as usize].take()
} else {
None
}
}
pub fn grow(self) -> Node256 {
let mut node256 = Node256::with_prefix(self.header.get_prefix());
node256.header.prefix_len = self.header.prefix_len;
for key in 0..256u16 {
let idx = self.child_index[key as usize];
if idx != 255 {
if let Some(child) = &self.children[idx as usize] {
node256.children[key as usize] = Some(child.clone());
}
}
}
node256.header.num_children = self.header.num_children;
node256
}
pub fn shrink(self) -> Node16 {
let mut node16 = Node16::with_prefix(self.header.get_prefix());
node16.header.prefix_len = self.header.prefix_len;
let mut idx = 0;
for key in 0..256u16 {
let slot = self.child_index[key as usize];
if slot != 255 {
if let Some(child) = &self.children[slot as usize] {
node16.keys[idx] = key as u8;
node16.children[idx] = Some(child.clone());
idx += 1;
if idx >= 16 {
break;
}
}
}
}
node16.header.num_children = idx as u16;
node16
}
pub fn iter_children(&self) -> impl Iterator<Item = (u8, &ArtNode)> + '_ {
(0..256u16).filter_map(move |key| {
let idx = self.child_index[key as usize];
if idx != 255 {
self.children[idx as usize].as_ref().map(|c| (key as u8, c))
} else {
None
}
})
}
}
#[derive(Debug, Clone)]
pub struct Node256 {
pub header: NodeHeader,
pub children: [Option<ArtNode>; 256],
}
impl Default for Node256 {
fn default() -> Self {
Self {
header: NodeHeader::default(),
children: std::array::from_fn(|_| None),
}
}
}
#[allow(clippy::indexing_slicing)] impl Node256 {
pub fn new() -> Self {
Self::default()
}
pub fn with_prefix(prefix: &[u8]) -> Self {
Self {
header: NodeHeader::with_prefix(prefix),
..Self::default()
}
}
pub fn should_shrink(&self) -> bool {
self.header.num_children <= 48
}
pub fn get_child(&self, key: u8) -> Option<&ArtNode> {
self.children[key as usize].as_ref()
}
pub fn get_child_mut(&mut self, key: u8) -> Option<&mut ArtNode> {
self.children[key as usize].as_mut()
}
pub fn add_child(&mut self, key: u8, child: ArtNode) -> bool {
if self.children[key as usize].is_none() {
self.header.num_children += 1;
}
self.children[key as usize] = Some(child);
true
}
pub fn remove_child(&mut self, key: u8) -> Option<ArtNode> {
let child = self.children[key as usize].take();
if child.is_some() {
self.header.num_children -= 1;
}
child
}
pub fn shrink(self) -> Node48 {
let mut node48 = Node48::with_prefix(self.header.get_prefix());
node48.header.prefix_len = self.header.prefix_len;
let mut slot = 0;
for key in 0..256u16 {
if let Some(child) = &self.children[key as usize] {
node48.child_index[key as usize] = slot as u8;
node48.children[slot] = Some(child.clone());
slot += 1;
if slot >= 48 {
break;
}
}
}
node48.header.num_children = slot as u16;
node48
}
pub fn iter_children(&self) -> impl Iterator<Item = (u8, &ArtNode)> + '_ {
(0..256u16).filter_map(move |key| {
self.children[key as usize].as_ref().map(|c| (key as u8, c))
})
}
}
impl ArtNode {
pub fn header(&self) -> &NodeHeader {
match self {
ArtNode::Node4(n) => &n.header,
ArtNode::Node16(n) => &n.header,
ArtNode::Node48(n) => &n.header,
ArtNode::Node256(n) => &n.header,
ArtNode::Leaf(_) => unreachable!("Leaf nodes don't have headers - use try_header() for safe access"),
}
}
pub fn header_mut(&mut self) -> &mut NodeHeader {
match self {
ArtNode::Node4(n) => &mut n.header,
ArtNode::Node16(n) => &mut n.header,
ArtNode::Node48(n) => &mut n.header,
ArtNode::Node256(n) => &mut n.header,
ArtNode::Leaf(_) => unreachable!("Leaf nodes don't have headers - use try_header_mut() for safe access"),
}
}
pub fn try_header(&self) -> Option<&NodeHeader> {
match self {
ArtNode::Node4(n) => Some(&n.header),
ArtNode::Node16(n) => Some(&n.header),
ArtNode::Node48(n) => Some(&n.header),
ArtNode::Node256(n) => Some(&n.header),
ArtNode::Leaf(_) => None,
}
}
pub fn try_header_mut(&mut self) -> Option<&mut NodeHeader> {
match self {
ArtNode::Node4(n) => Some(&mut n.header),
ArtNode::Node16(n) => Some(&mut n.header),
ArtNode::Node48(n) => Some(&mut n.header),
ArtNode::Node256(n) => Some(&mut n.header),
ArtNode::Leaf(_) => None,
}
}
pub fn is_leaf(&self) -> bool {
matches!(self, ArtNode::Leaf(_))
}
pub fn as_leaf(&self) -> Option<&LeafNode> {
match self {
ArtNode::Leaf(leaf) => Some(leaf),
_ => None,
}
}
pub fn as_leaf_mut(&mut self) -> Option<&mut LeafNode> {
match self {
ArtNode::Leaf(leaf) => Some(leaf),
_ => None,
}
}
pub fn get_child(&self, key: u8) -> Option<&ArtNode> {
match self {
ArtNode::Node4(n) => n.get_child(key),
ArtNode::Node16(n) => n.get_child(key),
ArtNode::Node48(n) => n.get_child(key),
ArtNode::Node256(n) => n.get_child(key),
ArtNode::Leaf(_) => None,
}
}
pub fn get_child_mut(&mut self, key: u8) -> Option<&mut ArtNode> {
match self {
ArtNode::Node4(n) => n.get_child_mut(key),
ArtNode::Node16(n) => n.get_child_mut(key),
ArtNode::Node48(n) => n.get_child_mut(key),
ArtNode::Node256(n) => n.get_child_mut(key),
ArtNode::Leaf(_) => None,
}
}
pub fn num_children(&self) -> u16 {
match self {
ArtNode::Node4(n) => n.header.num_children,
ArtNode::Node16(n) => n.header.num_children,
ArtNode::Node48(n) => n.header.num_children,
ArtNode::Node256(n) => n.header.num_children,
ArtNode::Leaf(_) => 0,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_node4_basic() {
let mut node = Node4::new();
assert!(node.add_child(b'a', ArtNode::Leaf(LeafNode::new(vec![b'a'], 1))));
assert!(node.add_child(b'b', ArtNode::Leaf(LeafNode::new(vec![b'b'], 2))));
assert!(node.add_child(b'c', ArtNode::Leaf(LeafNode::new(vec![b'c'], 3))));
assert!(node.add_child(b'd', ArtNode::Leaf(LeafNode::new(vec![b'd'], 4))));
assert!(node.is_full());
assert!(!node.add_child(b'e', ArtNode::Leaf(LeafNode::new(vec![b'e'], 5))));
assert!(node.get_child(b'a').is_some());
assert!(node.get_child(b'b').is_some());
assert!(node.get_child(b'e').is_none());
let removed = node.remove_child(b'b');
assert!(removed.is_some());
assert!(node.get_child(b'b').is_none());
assert_eq!(node.header.num_children, 3);
}
#[test]
fn test_node4_to_node16_growth() {
let mut node = Node4::new();
node.add_child(b'a', ArtNode::Leaf(LeafNode::new(vec![b'a'], 1)));
node.add_child(b'b', ArtNode::Leaf(LeafNode::new(vec![b'b'], 2)));
node.add_child(b'c', ArtNode::Leaf(LeafNode::new(vec![b'c'], 3)));
node.add_child(b'd', ArtNode::Leaf(LeafNode::new(vec![b'd'], 4)));
let node16 = node.grow();
assert_eq!(node16.header.num_children, 4);
assert!(node16.get_child(b'a').is_some());
assert!(node16.get_child(b'd').is_some());
}
#[test]
fn test_node256_direct_lookup() {
let mut node = Node256::new();
for i in 0..100 {
node.add_child(i, ArtNode::Leaf(LeafNode::new(vec![i], i as u64)));
}
assert_eq!(node.header.num_children, 100);
for i in 0..100 {
assert!(node.get_child(i).is_some());
}
assert!(node.get_child(200).is_none());
}
#[test]
fn test_prefix_compression() {
let mut node = Node4::with_prefix(b"prefix");
assert_eq!(node.header.prefix_len, 6);
assert_eq!(node.header.get_prefix(), b"prefix");
let long_prefix = b"this_is_a_very_long_prefix_that_exceeds_max";
let mut node2 = Node4::with_prefix(long_prefix);
assert_eq!(node2.header.prefix_len, long_prefix.len() as u32);
assert_eq!(node2.header.get_prefix(), &long_prefix[..MAX_PREFIX_LEN]);
}
}