1 个不稳定版本
0.1.0 | 2023年11月7日 |
---|
#1462 在 Rust 模式
195KB
4.5K SLoC
Kvtree
此库包含多个内存键/值容器,具有分层键和异构容器,因此与键关联的条目可以具有可变数量的值。
查询系统允许根据键和/或相关数据进行过滤。
键 & 掩码
键表示为元素数组(用户定义),可按公共前缀分组。
掩码可以匹配一个或多个键。
use kvtree::{Key, Mask, Match, mask::Atom, key::Ordering};
let parent = Key::new(1);
let mid = Key::from([1, 2]);
let child = Key::from([1, 2, 3]);
assert_eq!(parent.key_cmp(&child), Ordering::Parent);
assert_eq!(mid.key_cmp(&child), Ordering::Parent);
assert_eq!(child.key_cmp(&parent), Ordering::Child);
// matches any key that starts with `1` and has 1 or more parts after that
let mask = Mask::<i32, ()>::from([Atom::Key(1), Atom::Many]);
assert!(!mask.match_key(&parent));
assert!(mask.match_key(&child));
assert!(mask.match_key(&mid));
assert!(mask.match_children(&mid));
assert!(mask.match_children(&parent));
容器
存储 或 核心 是此库中的主要容器,但为了方便起见,也公开了构建块。
网格
网格包含同质数据,其中网格中的每一列都是唯一的类型。
示例:一个具有 A、B、C、D 作为列类型的网格。
+---------------+---+---+---+---+
| row index | A | B | C | D |
|---------------|---|---|---|---|
| 0 | A | B | C | D |
| 1 | A | B | C | D |
| ... | - | - | - | - |
+---------------+---+---+---+---+
索引
索引存储 0 或多个键以及键的前缀索引,这允许将索引中的键视为树。
插入和删除行为与网格相同。这意味着如果同时执行这两个操作,则键索引与网格行索引匹配。
表格
表格建立在网格和索引之上,将键索引(树索引)与网格索引关联起来。
示例:一个具有 A、B、C、D 作为列类型的表格。
+---------+---+---+---+---+
| key | A | B | C | D |
|---------|---|---|---|---|
| foo | A | B | C | D |
| foo.bar | A | B | C | D |
| ... | - | - | - | - |
+---------+---+---+---+---+
use kvtree::{Key, Table};
let k1 = Key::from(["foo", "bar"]);
let k2 = Key::from(["foo", "baz"]);
let mut table = Table::new();
table.insert(k1.clone(), ("hello", 123i32, 1u8)).unwrap();
table.insert(k2.clone(), ("world", 456i32, 2u8)).unwrap();
*table.get_mut::<&mut u8>(&k1).unwrap() *= 10;
assert_eq!(table.get::<&u8>(&Key::from(["foo", "bar"])), Some(&10));
assert_eq!(
table.iter_indexed::<(&u8, &&str)>().collect::<Vec<_>>(),
vec![(&k1, (&10, &"hello")), (&k2, (&2, &"world"))]
);
存储
存储是一组具有唯一键的表格。
存储中的表格根据与键关联的数据自动管理。
use kvtree::{Key, Store};
let k1 = Key::from(["foo", "bar"]);
let k2 = Key::from(["foo", "baz"]);
let mut store = Store::new();
store.insert(k1.clone(), ("hello", 123i32, 1u8)).unwrap();
store.insert(k2.clone(), ("world", false)).unwrap();
assert_eq!(store.len_tables(), 2);
assert_eq!(
store.iter::<(&u8, &&str)>().collect::<Vec<_>>(),
vec![(&k1, (&1, &"hello"))]
);
assert_eq!(
store.iter_indexed::<&&str>().collect::<Vec<_>>(),
vec![(&k1, &"hello"), (&k2, &"world")]
);
store.remove(&k1);
assert_eq!(store.len_tables(), 1);
核心
此结构封装了一个后进先出(LIFO)存储堆栈和访问控制。
访问控制模式与键和掩码相关联。
存在 4 种不同的访问模式(按优先级排序)
- 拒绝:阻止当前和上一层的读取和写入访问
- 只读:在当前层和上一层
- 新:表现得像它是键首次出现的第一层(防止读取和写入上一层,可以重置上一层模式)
- 写时复制:可以读取上一层的值,在当前层写入
- 引用:允许直接在当前层或父层中读取或写入数据。
只能修改堆栈的最顶层层的访问模式。
可以动态创建/删除层,从而允许精细调整对键的访问。
访问模式从给定层开始,到堆栈上的第一个存储层(从上到下)有效。
#[cfg(feature = "core-storage")] {
use kvtree::{core::Access, store::UpdateOpt, Core, Key};
let mut core = Core::<_, ()>::new();
let k1 = Key::from(["foo", "bar"]);
let k2 = Key::from(["foo", "baz"]);
let k3 = Key::from(["foo", "boo"]);
core.insert(k1.clone(), ("abc", 123)).unwrap();
core.insert(k2.clone(), (22,)).unwrap();
core.insert(k3.clone(), (23,)).unwrap();
assert_eq!(core.get::<&i32>(&k1), Some(&123));
core.set_key_access(k1.clone(), Access::Deny);
assert_eq!(core.get::<&i32>(&k1), None);
core.push_layer();
core.set_key_access(k1.clone(), Access::New);
core.set_key_access(k2.clone(), Access::Cow);
core.set_key_access(k3.clone(), Access::Ref);
assert_eq!(core.get::<&i32>(&k2), Some(&22));
assert_eq!(core.get::<&i32>(&k1), None);
core.upsert(k1.clone(), ("new value", false), UpdateOpt::Replace).unwrap();
assert_eq!(core.get::<&bool>(&k1), Some(&false));
core.upsert(k2.clone(), ("new value", true), UpdateOpt::Replace).unwrap();
assert_eq!(core.get::<&i32>(&k2), None);
assert_eq!(core.get::<&bool>(&k2), Some(&true));
core.upsert(k3.clone(), ("updated", true), UpdateOpt::Update).unwrap();
assert_eq!(
core.get::<(&bool, &&str, &i32)>(&k3),
Some((&true, &"updated", &23))
);
core.pop_layer();
assert_eq!(
core.get::<(&&str, &i32, &bool)>(&k3),
Some((&"updated", &23, &true))
);
assert_eq!(core.get::<&i32>(&k1), None);
assert_eq!(core.get::<&i32>(&k2), Some(&22));
}
贡献
发现问题或有建议?请随时提出问题。
依赖项
~3.5MB
~62K SLoC