5个版本
0.2.0 | 2023年3月31日 |
---|---|
0.1.3 | 2023年3月31日 |
0.1.2 | 2023年3月31日 |
0.1.1 | 2023年3月31日 |
0.1.0 | 2023年3月31日 |
#853 在 数据库接口
52KB
1.5K SLoC
verde
一款清爽的增量计算引擎。
什么是增量计算?
增量计算处理一个看似简单的问题
给定一个纯函数 f
和一些输入 x
,计算 f(x)
,并 记忆化 输出。下次,如果用相同的输入执行 f
,则返回记忆化的输出而不是重新计算。然而,如果输入发生变化,则重新计算值,并重复。
术语
verde 的核心组件是一个 数据库。数据库存储所有记忆化的数据(跟踪类型),以及跟踪每个记忆化函数的状态(一个 查询)。此外,数据库还允许对值进行内部化处理,以便它们是去重的,并且可以通过简单的 ID 检查进行比较(内部化类型)。最后,数据库还允许查询安全的 '旁路',以便在不成为查询输出的一部分的情况下收集诊断信息(可推送类型)。
入门
首先,我们必须定义 verde 将要跟踪的结构体。可以这样完成
#[derive(verde::Tracked, Eq, PartialEq)]
struct MyTrackedStruct {
#[id]
id: UniqueIdentifier,
value: u32,
}
标记为 #[id]
的字段用作每个跟踪类型的唯一标识符。它必须在每个查询中是唯一的(一个查询函数在给定不同输入时不得生成具有相同 ID 的结构体,但不同的查询可以)。注意,需要实现 Eq
特性才能实现 Tracked
,并且 ID 必须实现 Clone
、Eq
和 Hash
。
接下来,我们必须定义任何可推送的类型。
#[derive(verde::Pushable)]
struct MyPushableStruct {
value: u32,
}
实现 Pushable
不需要其他特性。
内部化作为一个便利功能提供
#[derive(verde::Interned, Eq, PartialEq, Hash)]
struct MyInternedStruct {
value: u32,
}
需要实现 Clone
、Eq
和 Hash
。
最后,我们必须定义查询函数。
#[verde::query]
fn double(ctx: &verde::Ctx, input: verde::Id<MyTrackedStruct>) -> MyTrackedStruct {
let interned = ctx.add(MyInternedStruct { value: 5 });
assert_eq!(ctx.geti(interned).value, 5);
ctx.push(MyPushableStruct { value: 5 });
let input = ctx.get(input);
MyTrackedStruct {
id: input.id,
value: input.value * 2,
}
}
查询是普通函数,必须将 &Ctx
作为第一个参数。它们可以像普通函数一样简单调用,verde 将透明地处理所有增量逻辑。
然而,在我们可以调用我们的查询之前,我们必须首先创建我们的数据库
#[verde::storage]
struct Storage(MyTrackedStruct, MyInternedStruct, MyPushableStruct, double);
#[verde::db]
struct Database(Storage);
使用 storage
属性来创建一个 存储结构体,该结构体包含数据库将知道的数据类型。将几个存储结构体组合在一起形成一个数据库。这种多层次的方法允许模块化设计,其中每个crate都可以定义一个存储结构体,而驱动crate只需包含它们。
最后,我们可以运行我们的查询
fn main() {
let mut db = Database::default();
let db = &mut db as &mut dyn verde::Db;
let input = db.set(MyTrackedStruct { id: UniqueIdentifier::new(), value: 5 });
let output = db.execute(|ctx| double(ctx, input));
assert_eq!(db.get(output).value, 10);
let mut pushables = db.get_all::<MyPushableStruct>();
assert_eq!(pushables.next().map(|x| x.value), Some(5));
assert_eq!(pushables.next(), None);
}
依赖项
~1.3–7MB
~44K SLoC