use super::core::{
trie_ref_root, trie_ref_root_borrowed, TrieRefLike, TrieRefNode, TrieRefNodeChar,
};
use crate::value::DictionaryValue;
use crate::{Dictionary, MappedDictionary, SyncStrategy};
use pathmap::zipper::{
ReadZipperOwned, ReadZipperUntracked, TrieRefBorrowed, TrieRefOwned, ZipperReadOnlySubtries,
};
use pathmap::PathMap;
#[inline]
fn value_at<V, R>(root: &R, term: &str) -> Option<V>
where
V: DictionaryValue,
R: TrieRefLike<V>,
{
root.descend_bytes(term.as_bytes()).val_cloned()
}
#[derive(Clone)]
pub struct PathMapSnapshot<V: DictionaryValue> {
root: TrieRefOwned<V>,
len: Option<usize>,
}
impl<V: DictionaryValue> PathMapSnapshot<V> {
#[inline]
pub fn from_map(map: PathMap<V>) -> Self {
Self {
root: trie_ref_root(map),
len: None,
}
}
#[inline]
pub fn from_map_ref(map: &PathMap<V>) -> Self {
Self {
root: trie_ref_root(map.clone()),
len: None,
}
}
#[inline]
pub fn from_trie_ref(root: TrieRefOwned<V>) -> Self {
Self { root, len: None }
}
#[inline]
pub fn from_read_zipper(zipper: ReadZipperOwned<V>) -> Self {
Self {
root: zipper.trie_ref_at_path::<&[u8]>(&[]),
len: None,
}
}
#[inline]
pub fn with_len(mut self, len: usize) -> Self {
self.len = Some(len);
self
}
#[inline]
pub fn root_ref(&self) -> &TrieRefOwned<V> {
&self.root
}
}
impl<V: DictionaryValue> Dictionary for PathMapSnapshot<V> {
type Node = TrieRefNode<V, TrieRefOwned<V>>;
#[inline]
fn root(&self) -> Self::Node {
TrieRefNode::new(self.root.clone())
}
#[inline]
fn len(&self) -> Option<usize> {
self.len
}
#[inline]
fn sync_strategy(&self) -> SyncStrategy {
SyncStrategy::Persistent
}
}
impl<V: DictionaryValue> MappedDictionary for PathMapSnapshot<V> {
type Value = V;
#[inline]
fn get_value(&self, term: &str) -> Option<Self::Value> {
value_at(&self.root, term)
}
}
#[derive(Clone)]
pub struct PathMapRef<'a, V: DictionaryValue> {
root: TrieRefBorrowed<'a, V>,
len: Option<usize>,
}
impl<'a, V: DictionaryValue> PathMapRef<'a, V> {
#[inline]
pub fn from_map(map: &'a PathMap<V>) -> Self {
Self {
root: trie_ref_root_borrowed(map),
len: None,
}
}
#[inline]
pub fn from_trie_ref(root: TrieRefBorrowed<'a, V>) -> Self {
Self { root, len: None }
}
#[inline]
pub fn from_read_zipper(zipper: &ReadZipperUntracked<'a, 'static, V>) -> Self {
Self {
root: zipper.trie_ref_at_path::<&[u8]>(&[]),
len: None,
}
}
#[inline]
pub fn with_len(mut self, len: usize) -> Self {
self.len = Some(len);
self
}
#[inline]
pub fn root_ref(&self) -> &TrieRefBorrowed<'a, V> {
&self.root
}
}
impl<'a, V: DictionaryValue> Dictionary for PathMapRef<'a, V> {
type Node = TrieRefNode<V, TrieRefBorrowed<'a, V>>;
#[inline]
fn root(&self) -> Self::Node {
TrieRefNode::new(self.root)
}
#[inline]
fn len(&self) -> Option<usize> {
self.len
}
#[inline]
fn sync_strategy(&self) -> SyncStrategy {
SyncStrategy::Persistent
}
}
impl<'a, V: DictionaryValue> MappedDictionary for PathMapRef<'a, V> {
type Value = V;
#[inline]
fn get_value(&self, term: &str) -> Option<Self::Value> {
value_at(&self.root, term)
}
}
#[derive(Clone)]
pub struct PathMapSnapshotChar<V: DictionaryValue> {
root: TrieRefOwned<V>,
len: Option<usize>,
}
impl<V: DictionaryValue> PathMapSnapshotChar<V> {
#[inline]
pub fn from_map(map: PathMap<V>) -> Self {
Self {
root: trie_ref_root(map),
len: None,
}
}
#[inline]
pub fn from_map_ref(map: &PathMap<V>) -> Self {
Self {
root: trie_ref_root(map.clone()),
len: None,
}
}
#[inline]
pub fn from_trie_ref(root: TrieRefOwned<V>) -> Self {
Self { root, len: None }
}
#[inline]
pub fn from_read_zipper(zipper: ReadZipperOwned<V>) -> Self {
Self {
root: zipper.trie_ref_at_path::<&[u8]>(&[]),
len: None,
}
}
#[inline]
pub fn with_len(mut self, len: usize) -> Self {
self.len = Some(len);
self
}
}
impl<V: DictionaryValue> Dictionary for PathMapSnapshotChar<V> {
type Node = TrieRefNodeChar<V, TrieRefOwned<V>>;
#[inline]
fn root(&self) -> Self::Node {
TrieRefNodeChar::new(self.root.clone())
}
#[inline]
fn len(&self) -> Option<usize> {
self.len
}
#[inline]
fn sync_strategy(&self) -> SyncStrategy {
SyncStrategy::Persistent
}
}
impl<V: DictionaryValue> MappedDictionary for PathMapSnapshotChar<V> {
type Value = V;
#[inline]
fn get_value(&self, term: &str) -> Option<Self::Value> {
value_at(&self.root, term)
}
}
#[derive(Clone)]
pub struct PathMapRefChar<'a, V: DictionaryValue> {
root: TrieRefBorrowed<'a, V>,
len: Option<usize>,
}
impl<'a, V: DictionaryValue> PathMapRefChar<'a, V> {
#[inline]
pub fn from_map(map: &'a PathMap<V>) -> Self {
Self {
root: trie_ref_root_borrowed(map),
len: None,
}
}
#[inline]
pub fn from_trie_ref(root: TrieRefBorrowed<'a, V>) -> Self {
Self { root, len: None }
}
#[inline]
pub fn from_read_zipper(zipper: &ReadZipperUntracked<'a, 'static, V>) -> Self {
Self {
root: zipper.trie_ref_at_path::<&[u8]>(&[]),
len: None,
}
}
#[inline]
pub fn with_len(mut self, len: usize) -> Self {
self.len = Some(len);
self
}
}
impl<'a, V: DictionaryValue> Dictionary for PathMapRefChar<'a, V> {
type Node = TrieRefNodeChar<V, TrieRefBorrowed<'a, V>>;
#[inline]
fn root(&self) -> Self::Node {
TrieRefNodeChar::new(self.root)
}
#[inline]
fn len(&self) -> Option<usize> {
self.len
}
#[inline]
fn sync_strategy(&self) -> SyncStrategy {
SyncStrategy::Persistent
}
}
impl<'a, V: DictionaryValue> MappedDictionary for PathMapRefChar<'a, V> {
type Value = V;
#[inline]
fn get_value(&self, term: &str) -> Option<Self::Value> {
value_at(&self.root, term)
}
}
#[cfg(test)]
mod tests {
use super::*;
use pathmap::PathMap;
fn assert_send_sync<T: Send + Sync>() {}
fn map_of(pairs: &[(&str, u32)]) -> PathMap<u32> {
let mut map = PathMap::new();
for (term, value) in pairs {
map.insert(term.as_bytes(), *value);
}
map
}
#[test]
fn snapshot_contains_and_get_value() {
let snap = PathMapSnapshot::from_map(map_of(&[("hello", 1), ("help", 2), ("world", 3)]))
.with_len(3);
assert_eq!(snap.len(), Some(3));
assert!(!snap.is_empty());
assert!(snap.contains("hello"));
assert!(snap.contains("help"));
assert!(!snap.contains("hel"));
assert_eq!(snap.get_value("hello"), Some(1));
assert_eq!(snap.get_value("world"), Some(3));
assert_eq!(snap.get_value("missing"), None);
assert_eq!(snap.sync_strategy(), SyncStrategy::Persistent);
}
#[test]
fn cow_snapshot_is_decoupled_from_later_mutations() {
let mut map = map_of(&[("alpha", 1)]);
let snap = PathMapSnapshot::from_map_ref(&map);
map.insert(b"beta", 2);
assert!(snap.contains("alpha"));
assert!(!snap.contains("beta"));
}
#[test]
fn borrowed_ref_reads_live_map() {
let map = map_of(&[("cat", 1), ("car", 2)]);
let dict = PathMapRef::from_map(&map);
assert!(dict.contains("cat"));
assert!(dict.contains("car"));
assert!(!dict.contains("ca"));
assert_eq!(dict.get_value("cat"), Some(1));
assert_eq!(dict.len(), None);
assert!(!dict.is_empty());
}
#[test]
fn from_trie_ref_scopes_to_subtrie() {
let map = map_of(&[("apple", 1), ("apply", 2), ("banana", 3)]);
let sub = PathMapRef::from_trie_ref(map.trie_ref_at_path(b"appl"));
let root = sub.root();
use crate::DictionaryNode;
let mut labels: Vec<u8> = root.edges().map(|(b, _)| b).collect();
labels.sort_unstable();
assert_eq!(labels, vec![b'e', b'y']);
}
#[test]
fn from_read_zipper_owned_and_borrowed() {
let map = map_of(&[("foo", 1), ("foobar", 2)]);
let rz = map.read_zipper();
let borrowed = PathMapRef::from_read_zipper(&rz);
assert!(borrowed.contains("foo"));
assert!(borrowed.contains("foobar"));
drop(rz);
let owned_rz = map.clone().into_read_zipper(b"foo");
let snap = PathMapSnapshot::from_read_zipper(owned_rz);
assert!(snap.contains(""));
assert!(snap.contains("bar"));
assert!(!snap.contains("foo"));
}
#[test]
fn char_snapshot_unicode() {
let snap = PathMapSnapshotChar::from_map(map_of(&[("café", 1), ("中文", 2), ("🎉", 3)]));
assert!(snap.contains("café"));
assert!(snap.contains("中文"));
assert!(snap.contains("🎉"));
assert!(!snap.contains("cafe"));
assert_eq!(snap.get_value("中文"), Some(2));
}
#[test]
fn char_ref_unicode() {
let map = map_of(&[("naïve", 1), ("日本語", 2)]);
let dict = PathMapRefChar::from_map(&map);
assert!(dict.contains("naïve"));
assert!(dict.contains("日本語"));
assert_eq!(dict.get_value("naïve"), Some(1));
}
#[test]
fn empty_snapshot_queries_safely() {
let snap = PathMapSnapshot::<u32>::from_map(PathMap::new());
assert!(!snap.contains("anything"));
assert_eq!(snap.get_value("anything"), None);
assert_eq!(snap.len(), None);
}
#[test]
fn snapshot_and_ref_adapters_are_send_sync() {
assert_send_sync::<PathMapSnapshot<u32>>();
assert_send_sync::<PathMapSnapshotChar<u32>>();
assert_send_sync::<PathMapRef<'static, u32>>();
assert_send_sync::<PathMapRefChar<'static, u32>>();
}
}