1 个不稳定版本

0.1.0 2023年11月7日

#1462Rust 模式

BSD-3-Clause

195KB
4.5K SLoC

Kvtree

Crate link Documentation License

此库包含多个内存键/值容器,具有分层键和异构容器,因此与键关联的条目可以具有可变数量的值。

查询系统允许根据键和/或相关数据进行过滤。

键 & 掩码

键表示为元素数组(用户定义),可按公共前缀分组。

掩码可以匹配一个或多个键。

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