5 个版本 (破坏性更新)
使用旧的 Rust 2015
0.5.0 | 2018 年 3 月 6 日 |
---|---|
0.4.0 | 2017 年 9 月 27 日 |
0.3.0 | 2017 年 8 月 16 日 |
0.2.0 | 2017 年 7 月 21 日 |
0.1.0 | 2017 年 7 月 7 日 |
#1023 in Rust 模式
56KB
1K SLoC
Adhesion
一组用于 Rust 中设计接触的宏。该库的设计灵感来源于 D 的合同编程功能。以下是一个快速示例
use std::i32;
contract! {
fn add_one_to_odd(x: i32) -> i32 {
post(y) {
assert!(y - 1 == x, "reverse operation did not produce input");
}
body {
x + 1
}
pre {
assert!(x != i32::MAX, "cannot add one to input at max of number range");
assert!(x % 2 != 0, "evens ain't appropriate here");
}
}
}
assert!(add_one_to_odd(3) == 4);
assert!(add_one_to_odd(5) == 6);
assert_that!(add_one_to_odd(2), panics);
assert_that!(add_one_to_odd(i32::MAX), panics);
在上面的示例中,pre
在 body
之前运行,而 post
,其返回值绑定到 y
,在之后运行。我们还可以使用 double_check
块定义检查,它将在 body
运行前后进行检查
struct Counter {
count: u32,
max: u32
}
contract! {
fn increment_counter(c: &mut Counter) {
double_check {
assert!(c.count <= c.max, "counter max has been exceeded");
}
body {
c.count += 1;
}
}
}
let mut counter = Counter { count: 0, max: 3 };
macro_rules! assert_incremented_eq {
($e: expr) => ({
increment_counter(&mut counter);
assert!(counter.count == $e, format!("expected counter to be {}, got {}", $e, counter.count));
})
}
assert_incremented_eq!(1);
assert_incremented_eq!(2);
assert_incremented_eq!(3);
assert_incremented_eq!(4); // panics!
实际上,上述示例可以替换为 impl
块中的顶级 double_check
块,这样就不需要重复代码即可为每个方法维护不变性
struct Counter {
count: u32,
max: u32
}
impl Counter {
contract! {
double_check {
assert!(self.count <= self.max, "counter max has been exceeded");
}
fn increment(&mut self) {
body {
self.count.checked_add();
}
}
}
}
let mut counter = Counter { count: 0, max: 3 };
macro_rules! assert_incremented_eq {
($e: expr) => ({
counter.increment();
assert!(counter.count == $e, format!("expected counter to be {}, got {}", $e, counter.count));
})
}
assert_incremented_eq!(1);
assert_incremented_eq!(2);
assert_incremented_eq!(3);
assert_incremented_eq!(4); // panics!
很酷,对吧?想了解更多关于这个包的详细信息以及你可以用它做什么,请查看文档。
常见问题解答
为什么叫“Adhesion”?
这个库被称为“Adhesion”,是为了参考一种称为“粘附性合同”的特定类型的合同,也称为“要么全有要么全无”的合同。编程中的断言绝对是一种“要么全有要么全无”——如果断言失败,你必须修复断言的条件,或者改变断言本身。听起来很合适!
为什么将 D 的 invariant
重命名为 double_check
?
在v0.2.0版本发布后,@eternaleye在Reddit论坛讨论区中指出,在技术层面上,“不变性”意味着代码中所有操作之间必须严格维护的强烈保证。这种保证并不是D语言中invariant
块的行为所提供的,正如@eternaleye提供的链接所示。
语义很重要,尤其是在像基于合同的软件设计这样的系统中,试图引入更多严谨性。因此,D语言中称为invariant
的联合前检查和后检查块,在这个库中被称为double_check
。
许可
本项目根据您的选择,采用MIT许可协议或Apache 2.0许可协议双重许可。
- Adhesion使用了rust-parse-generics项目组件的修改版本。这里的原始版本和修改版本都使用与本项目相同的双重许可。
贡献者
- @ErichDonGubler,原始作者
- @dzamlo,为提供各种重要功能提供帮助。
- @DanielKeep,他在宏中解析和使用泛型以及Adhesion在开发涉及泛型的功能期间提供指导方面做出了巨大贡献。
- @eternaleye,他带来了安全专业知识,并推动了
double_check
与D语言中的invariant
的分歧。
无运行时依赖
~165KB