10 个版本
0.4.0 | 2020 年 12 月 21 日 |
---|---|
0.3.2 | 2020 年 2 月 17 日 |
0.3.1 | 2020 年 1 月 9 日 |
0.2.4 | 2020 年 1 月 9 日 |
0.1.0 | 2020 年 1 月 3 日 |
#87 in 缓存
285KB
5K SLoC
DAG 感知工件构建器
Rust 包用于管理以有向无环图(DAG)方式连接的工件构建和缓存,即工件可能依赖于其他工件。
此包提供的缓存功能在工件构建器使用可消耗资源、构建过程是重量级操作或需要在构建器之间正确保留给定的 DAG 依赖结构时特别有用。
最小 Rust 版本:1.40
基本概念
daab 的基本概念围绕着 构建器,构建器是用户提供的实现 Builder
特性的结构体。该特性本质上有一个关联类型 Artifact
和一个方法 build
,后者将生成一个 Artifact
类型的值,随后将被称为 工件。为了能够依赖其他构建器的工件,build
方法还提供了一个 Resolver
,允许检索其他工件的工件。
为了允许构建器和工件形成一个有向无环图,此包在其核心提供了一个工件 Cache
,用于保存构建器的工件,以防止构建器生成多个相同的工件。因此,不同的构建器可以依赖相同的构建器并从 Cache
获取相同的工件。
为了能够共享构建器和工件,此包还提供了一个 罐 和 箱 的概念,在最基本的情况下,它们分别是一个不可见的 Rc<dyn Any>
和一个透明的 Rc<T>
。这些是通过例如 Cache
的泛型参数引用的。有关更多详细信息,请参阅 canning
模块。
除了罐装之外,Cache
还期望构建器被包裹在一个不可见的 Blueprint
中,以强制封装,即它阻止用户访问内部结构(实现 Builder
特性的结构),而只允许 Cache
本身调用其 build
方法。
入门指南
对于基本概念(如上所述),存在简化特性,跳过了更高级的功能。其中之一是rc
模块中的SimpleBuilder
,它使用Rc
进行缓存,并为所有上述类型提供了简化的别名(最小泛型参数)。要开始使用,rc
模块可能是最佳起点。
示例
use std::rc::Rc;
use daab::*;
// Simple artifact
#[derive(Debug)]
struct Leaf {
//...
}
// Simple builder
#[derive(Debug)]
struct BuilderLeaf {
// ...
}
impl BuilderLeaf {
pub fn new() -> Self {
Self {
// ...
}
}
}
impl rc::SimpleBuilder for BuilderLeaf {
type Artifact = Leaf;
fn build(&self, _resolver: &mut rc::Resolver) -> Self::Artifact {
Leaf{
// ...
}
}
}
// Composed artifact, linking to a Leaf
#[derive(Debug)]
struct Node {
leaf: Rc<Leaf>, // Dependency artifact
value: u8, // Some custom value
// ...
}
// Composed builder, depending on BuilderLeaf
#[derive(Debug)]
struct BuilderNode {
builder_leaf: rc::Blueprint<BuilderLeaf>, // Dependency builder
// ...
}
impl BuilderNode {
pub fn new(builder_leaf: rc::Blueprint<BuilderLeaf>) -> Self {
Self {
builder_leaf,
// ...
}
}
}
use std::any::Any;
impl rc::Builder for BuilderNode {
type Artifact = Node;
type DynState = u8;
type Err = Never;
fn build(&self, resolver: &mut rc::Resolver<Self::DynState>) -> Result<Rc<Self::Artifact>, Never> {
// Resolve Blueprint to its artifact
// Unpacking because the Err type is Never.
let leaf = resolver.resolve(&self.builder_leaf).unpack();
Ok(Node {
leaf,
value: *resolver.my_state(),
// ...
}.into())
}
fn init_dyn_state(&self) -> Self::DynState {
42
}
}
// The cache to storing already created artifacts
let mut cache = rc::Cache::new();
// Constructing builders
let leaf_builder = rc::Blueprint::new(BuilderLeaf::new());
let node_builder_1 = rc::Blueprint::new(BuilderNode::new(leaf_builder.clone()));
let node_builder_2 = rc::Blueprint::new(BuilderNode::new(leaf_builder.clone()));
// Using the cache to access the artifacts from the builders
// The same builder results in same artifact
assert!(Rc::ptr_eq(&cache.get(&node_builder_1).unpack(), &cache.get(&node_builder_1).unpack()));
// Different builders result in different artifacts
assert!( ! Rc::ptr_eq(&cache.get(&node_builder_1).unpack(), &cache.get(&node_builder_2).unpack()));
// Different artifacts may link the same dependent artifact
assert!(Rc::ptr_eq(&cache.get(&node_builder_1).unpack().leaf, &cache.get(&node_builder_2).unpack().leaf));
// Purge builder 2 to ensure the following does not affect it
cache.purge(&node_builder_2);
// Test dynamic state
assert_eq!(cache.get(&node_builder_1).unpack().value, 42);
// Change state
*cache.dyn_state_mut(&node_builder_1) = 127.into();
// Without invalidation, the cached artefact remains unchanged
assert_eq!(cache.dyn_state(&node_builder_1), &127);
// Invalidate node, and ensure it made use of the state
assert_eq!(cache.get(&node_builder_1).unpack().value, 127);
// State of node 2 remains unchanged
assert_eq!(cache.get_dyn_state(&node_builder_2), None);
assert_eq!(cache.get(&node_builder_2).unpack().value, 42);
调试
daab
附带丰富的调试工具。然而,为了将生产影响降至最低,调试功能被封装在diagnostics
特性之后。
当然,调试特性是为了让此crate的用户调试他们的图。因此,它更像是一个诊断特性(因此得名)。诊断由一个Doctor
执行,这是一个接收各种内部事件以记录、打印或以其他方式帮助处理错误的特性。
已采取措施确保diagnostics
特性具有广泛的适用性,同时保持非diagnostics
API与diagnostics
-API的兼容性,这意味着未使用diagnostics
特性的项目可以轻松转换为使用diagnostics
,通常只需将Cache::new()
替换为Cache::new_with_doctor()
即可。为了存储Doctor
,Cache
是泛型到医生,这对于其创建和按值存储很重要。其余时间,Cache
使用dyn Doctor
作为其默认泛型参数。为了便于在它们之间进行转换,所有可创建的Cache
(即不是Cache<dyn Doctor>
)都实现了DerefMut
到&mut Cache<dyn Doctor>
,它实现了所有重要的方法。
特性
此crate提供以下特性
-
diagnostics
启用了详尽的图和缓存交互调试。它向Cache
添加了new_with_doctor()
函数,并添加了带有Doctor
特性定义和一些默认Doctor
的diagnostics
模块。 -
tynm
启用对tynm
crate的可选依赖,该crate添加了缩写类型名的功能,一些默认的Doctor
使用它,因此它仅与diagnostics
特性一起使用。 -
unsized
启用通过BlueprintUnsized::into_unsized
在无尺寸构建器之间进行更好的转换。此特性需要Nightly Rust。
许可
根据Apache License,版本2.0许可(LICENSE或https://apache.ac.cn/licenses/LICENSE-2.0)。
贡献
除非您明确声明,否则您根据Apache-2.0许可证定义的任何有意提交以包含在本项目中的贡献,应按上述方式许可,不附加任何额外条款或条件。
依赖项
~195KB