#[allow(unused_imports)]
use crate::sync_compat::RwLock;
#[allow(unused_imports)]
use std::sync::Arc;
#[allow(unused_imports)]
use super::bucket::StringBucket;
use super::dict_impl::PersistentARTrie;
#[allow(unused_imports)]
use super::transitions::ChildNode;
use super::SharedARTrie;
use crate::persistent_artrie_core::shared_access::SharedTrieAccess;
use crate::persistent_artrie_core::overlay::flip::LockFreeOverlay;
use crate::value::DictionaryValue;
use crate::zipper::{DictZipper, ValuedDictZipper};
#[derive(Clone)]
pub struct PersistentARTrieZipper<V: DictionaryValue = ()> {
trie: SharedARTrie<V>,
path: Vec<u8>,
}
impl<V: DictionaryValue> PersistentARTrieZipper<V> {
pub fn new(trie: SharedARTrie<V>) -> Self {
PersistentARTrieZipper {
trie,
path: Vec::new(),
}
}
pub fn new_from_shared(trie: SharedARTrie<V>) -> Self {
Self::new(trie)
}
pub fn current_path(&self) -> &[u8] {
&self.path
}
}
impl<V: DictionaryValue> DictZipper for PersistentARTrieZipper<V> {
type Unit = u8;
fn is_final(&self) -> bool {
let guard = self.trie.read();
self.is_final_at_path(&guard, &self.path)
}
fn descend(&self, label: Self::Unit) -> Option<Self> {
let guard = self.trie.read();
let mut new_path = self.path.clone();
new_path.push(label);
if self.has_path(&guard, &new_path) {
Some(PersistentARTrieZipper {
trie: self.trie.clone(),
path: new_path,
})
} else {
None
}
}
fn path(&self) -> Vec<Self::Unit> {
self.path.clone()
}
fn children(&self) -> impl Iterator<Item = (Self::Unit, Self)> {
let children: Vec<u8> = {
let guard = self.trie.read();
self.get_children_at_path(&guard, &self.path)
};
let trie_clone = self.trie.clone();
let base_path = self.path.clone();
children.into_iter().map(move |label| {
let mut new_path = base_path.clone();
new_path.push(label);
(
label,
PersistentARTrieZipper {
trie: trie_clone.clone(),
path: new_path,
},
)
})
}
}
impl<V: DictionaryValue> PersistentARTrieZipper<V> {
fn has_path(&self, inner: &PersistentARTrie<V>, path: &[u8]) -> bool {
inner.overlay_navigate(path).is_some()
}
fn is_final_at_path(&self, inner: &PersistentARTrie<V>, path: &[u8]) -> bool {
inner.overlay_navigate(path).is_some_and(|n| n.is_final())
}
fn get_children_at_path(&self, inner: &PersistentARTrie<V>, path: &[u8]) -> Vec<u8> {
match inner.overlay_navigate(path) {
Some(node) => node.iter_children().map(|(k, _)| *k).collect(),
None => Vec::new(),
}
}
}
impl<V: DictionaryValue> ValuedDictZipper for PersistentARTrieZipper<V> {
type Value = V;
fn value(&self) -> Option<Self::Value> {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_zipper<V: DictionaryValue>(dict: PersistentARTrie<V>) -> PersistentARTrieZipper<V> {
let shared: SharedARTrie<V> = Arc::new(dict);
PersistentARTrieZipper::new(shared)
}
#[test]
fn test_root_zipper_not_final() {
let dict: PersistentARTrie<()> = PersistentARTrie::new();
dict.insert("test");
let zipper = make_zipper(dict);
assert!(!zipper.is_final());
}
#[test]
fn test_descend_single_term() {
let dict: PersistentARTrie<()> = PersistentARTrie::new();
dict.insert("cat");
let zipper = make_zipper(dict);
let c = zipper.descend(b'c').expect("should have 'c'");
let a = c.descend(b'a').expect("should have 'a'");
let t = a.descend(b't').expect("should have 't'");
assert!(t.is_final());
}
#[test]
fn test_descend_nonexistent() {
let dict: PersistentARTrie<()> = PersistentARTrie::new();
dict.insert("cat");
let zipper = make_zipper(dict);
assert!(zipper.descend(b'x').is_none());
}
#[test]
fn test_children() {
let dict: PersistentARTrie<()> = PersistentARTrie::new();
dict.insert("cat");
dict.insert("car");
dict.insert("can");
let zipper = make_zipper(dict);
let children: Vec<_> = zipper.children().collect();
assert_eq!(children.len(), 1);
assert_eq!(children[0].0, b'c');
}
#[test]
fn test_path() {
let dict: PersistentARTrie<()> = PersistentARTrie::new();
dict.insert("cat");
let zipper = make_zipper(dict);
assert!(zipper.path().is_empty());
let c = zipper.descend(b'c').unwrap();
assert_eq!(c.path(), vec![b'c']);
let a = c.descend(b'a').unwrap();
assert_eq!(a.path(), vec![b'c', b'a']);
}
#[test]
fn test_empty_string() {
let dict: PersistentARTrie<()> = PersistentARTrie::new();
dict.insert("");
dict.insert("test");
let zipper = make_zipper(dict);
assert!(zipper.is_final()); }
#[test]
fn test_clone() {
let dict: PersistentARTrie<()> = PersistentARTrie::new();
dict.insert("test");
let zipper1 = make_zipper(dict);
let zipper2 = zipper1.clone();
assert_eq!(zipper1.path(), zipper2.path());
assert_eq!(zipper1.is_final(), zipper2.is_final());
}
#[test]
fn test_deep_navigation_with_many_terms() {
let dict: PersistentARTrie<()> = PersistentARTrie::new();
for i in 0..100 {
let term = format!("prefix_{:03}_suffix", i);
dict.insert(&term);
}
let zipper = make_zipper(dict);
let mut current = zipper;
for byte in b"prefix_050_suffix" {
current = current.descend(*byte).expect("should be able to descend");
}
assert!(current.is_final());
}
#[test]
fn test_children_with_many_terms() {
let dict: PersistentARTrie<()> = PersistentARTrie::new();
dict.insert("apple");
dict.insert("banana");
dict.insert("cherry");
dict.insert("date");
dict.insert("elderberry");
let zipper = make_zipper(dict);
let children: Vec<u8> = zipper.children().map(|(b, _)| b).collect();
assert_eq!(children.len(), 5);
assert!(children.contains(&b'a'));
assert!(children.contains(&b'b'));
assert!(children.contains(&b'c'));
assert!(children.contains(&b'd'));
assert!(children.contains(&b'e'));
}
#[test]
fn test_recursive_has_path_through_nested_art() {
let dict: PersistentARTrie<()> = PersistentARTrie::new();
for prefix in &["aa", "ab", "ac", "ad"] {
for suffix in &["1", "2", "3", "4"] {
let term = format!("{}{}", prefix, suffix);
dict.insert(&term);
}
}
let zipper = make_zipper(dict);
let a = zipper.descend(b'a').expect("should have 'a'");
let ab = a.descend(b'b').expect("should have 'b'");
let ab3 = ab.descend(b'3').expect("should have '3'");
assert!(ab3.is_final());
let aa = a.descend(b'a').expect("should have 'a'");
assert!(aa.descend(b'x').is_none());
}
}