use super::bucket::StringBucket;
use super::nodes::Node;
#[cfg(test)]
use super::nodes::Node4;
use super::swizzled_ptr::SwizzledPtr;
#[derive(Debug, Clone)]
pub enum ChildNode {
Bucket(StringBucket),
ArtNode {
node: Node,
is_final: bool,
value: Option<Vec<u8>>,
children: Vec<(u8, ChildNode)>,
},
DiskRef {
ptr: SwizzledPtr,
},
}
impl ChildNode {
pub fn bucket(b: StringBucket) -> Self {
ChildNode::Bucket(b)
}
pub fn art_node(node: Node, is_final: bool, value: Option<Vec<u8>>) -> Self {
ChildNode::ArtNode {
node,
is_final,
value,
children: Vec::new(),
}
}
pub fn art_node_with_children(
node: Node,
is_final: bool,
value: Option<Vec<u8>>,
children: Vec<(u8, ChildNode)>,
) -> Self {
ChildNode::ArtNode {
node,
is_final,
value,
children,
}
}
pub fn disk_ref(ptr: SwizzledPtr) -> Self {
ChildNode::DiskRef { ptr }
}
pub fn is_bucket(&self) -> bool {
matches!(self, ChildNode::Bucket(_))
}
pub fn is_disk_ref(&self) -> bool {
matches!(self, ChildNode::DiskRef { .. })
}
pub fn as_disk_ref(&self) -> Option<&SwizzledPtr> {
match self {
ChildNode::DiskRef { ptr } => Some(ptr),
_ => None,
}
}
#[inline]
pub fn needs_persistence(&self) -> bool {
match self {
ChildNode::Bucket(_) => {
true
}
ChildNode::ArtNode { node, .. } => node.header().needs_persistence(),
ChildNode::DiskRef { .. } => {
false
}
}
}
#[inline]
pub fn mark_has_dirty_descendants(&mut self) {
if let ChildNode::ArtNode { node, .. } = self {
node.header_mut().set_has_dirty_descendants(true);
}
}
#[inline]
pub fn clear_dirty_flags(&mut self) {
if let ChildNode::ArtNode { node, .. } = self {
node.header_mut().clear_dirty_flags();
}
}
#[inline]
pub fn mark_dirty(&mut self) {
if let ChildNode::ArtNode { node, .. } = self {
node.header_mut().set_dirty(true);
}
}
pub fn as_bucket(&self) -> Option<&StringBucket> {
match self {
ChildNode::Bucket(b) => Some(b),
_ => None,
}
}
pub fn as_bucket_mut(&mut self) -> Option<&mut StringBucket> {
match self {
ChildNode::Bucket(b) => Some(b),
_ => None,
}
}
pub fn as_art_node(&self) -> Option<(&Node, bool, &Option<Vec<u8>>, &Vec<(u8, ChildNode)>)> {
match self {
ChildNode::ArtNode {
node,
is_final,
value,
children,
} => Some((node, *is_final, value, children)),
_ => None,
}
}
pub fn as_art_node_mut(
&mut self,
) -> Option<(
&mut Node,
&mut bool,
&mut Option<Vec<u8>>,
&mut Vec<(u8, ChildNode)>,
)> {
match self {
ChildNode::ArtNode {
node,
is_final,
value,
children,
} => Some((node, is_final, value, children)),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_child_node_enum() {
let bucket = StringBucket::new();
let child = ChildNode::bucket(bucket);
assert!(child.is_bucket());
assert!(child.as_bucket().is_some());
let node = Node::N4(Box::new(Node4::new()));
let child = ChildNode::art_node(node, false, None);
assert!(!child.is_bucket());
assert!(child.as_bucket().is_none());
}
#[test]
fn test_child_node_needs_persistence_bucket() {
let bucket = StringBucket::new();
let child = ChildNode::bucket(bucket);
assert!(child.needs_persistence());
}
#[test]
fn test_child_node_needs_persistence_art_node() {
let node = Node::N4(Box::new(Node4::new()));
let mut child = ChildNode::art_node_with_children(node, false, None, Vec::new());
assert!(!child.needs_persistence());
child.mark_dirty();
assert!(child.needs_persistence());
child.clear_dirty_flags();
assert!(!child.needs_persistence());
child.mark_has_dirty_descendants();
assert!(child.needs_persistence());
child.clear_dirty_flags();
assert!(!child.needs_persistence());
}
#[test]
fn test_child_node_needs_persistence_disk_ref() {
let ptr = SwizzledPtr::null();
let child = ChildNode::disk_ref(ptr);
assert!(!child.needs_persistence());
}
#[test]
fn test_child_node_dirty_flag_methods() {
let node = Node::N4(Box::new(Node4::new()));
let mut child = ChildNode::art_node_with_children(node, false, None, Vec::new());
child.mark_dirty();
if let ChildNode::ArtNode { node, .. } = &child {
assert!(node.header().is_dirty());
}
child.clear_dirty_flags();
child.mark_has_dirty_descendants();
if let ChildNode::ArtNode { node, .. } = &child {
assert!(node.header().has_dirty_descendants());
assert!(!node.header().is_dirty());
}
child.mark_dirty();
child.clear_dirty_flags();
if let ChildNode::ArtNode { node, .. } = &child {
assert!(!node.header().is_dirty());
assert!(!node.header().has_dirty_descendants());
}
}
#[test]
fn test_child_node_dirty_methods_on_bucket() {
let bucket = StringBucket::new();
let mut child = ChildNode::bucket(bucket);
child.mark_dirty();
child.mark_has_dirty_descendants();
child.clear_dirty_flags();
assert!(child.is_bucket());
}
#[test]
fn test_child_node_dirty_methods_on_disk_ref() {
let ptr = SwizzledPtr::null();
let mut child = ChildNode::disk_ref(ptr);
child.mark_dirty();
child.mark_has_dirty_descendants();
child.clear_dirty_flags();
assert!(child.is_disk_ref());
}
}