4 个版本
0.2.1 | 2024 年 4 月 5 日 |
---|---|
0.2.0 | 2024 年 4 月 5 日 |
0.1.1 | 2024 年 4 月 5 日 |
0.1.0 | 2024 年 4 月 5 日 |
#944 在 Rust 模式
每月 25 次下载
用于 prism-compiler
15KB
260 行
彻底遍历
生成类型所有值的特性和基于属性的测试宏。
关于
此包提供了一个特性行为,用于生成类型(在一定深度内)的所有值。它还提供了一个派生宏,该宏会为您派生此特性。最后,它提供了一个测试宏,该宏会对类型的所有值运行基于属性的测试。
示例
#[derive(Debug, Exhaustive)]
enum Test1 { A, B, }
#[derive(Debug, Exhaustive)]
struct Test2 { a: bool }
#[exhaustive_test]
fn test(v: Test1, w: Test2) {
println!("{v:?} {w:?}");
}
A Test2 { a: false }
A Test2 { a: true }
B Test2 { a: false }
B Test2 { a: true }
任意长度的类型(递归类型,容器类型)
为了为递归类型或如 Vec
这样的任意长度类型实现 Exhaustive
,此包支持限制类型的大小。这是通过限制在类型生成过程中所做的选择数量来实现的。
在使用 exhaustive_test
宏时,您可以使用以下方式限制选择数量:
#[exhaustive_test(20)]
在生成类型时所做的选择数量不保证在版本之间保持稳定,尽管它始终保证与内存中类型的大小呈线性关系。这意味着对于大多数类型,选择数量与测试的运行时间呈指数关系。推荐的方式是根据测试期望的运行时间进行实验性选择。
详情
标准库类型
此特性对大多数标准库类型实现了,例如 Vec
、Result
、Option
、Box
、HashMap
、HashSet
、元组、数组等。主要的例外是数值类型,因为它们的增长速度太快,无法进行彻底测试。
派生宏
派生宏可以为任何具有所有字段都实现 Exhaustive
的 struct
或 enum
派生 Exhaustive
。为此,需要启用此包的 macros
功能。默认情况下,此功能是启用的。
手动实现
可以手动实现此特性。特性行为的签名是
trait Exhaustive: Sized {
fn generate(u: &mut DataSourceTaker) -> Result<Self>;
}
DataSourceTaker
有两个重要的函数,可用于生成您的类型
fn choice(&mut self, range: usize) -> Result<usize>;
fn iter_of<T: Exhaustive>(&mut self) -> Result<DataSourceTakerIter<T>>;
choice
将生成一个在0..range
范围内的数字。这可以用来选择枚举的一个变体,或者在生成数据类型时做出任何其他选择。iter_of
将生成一个T
类型的迭代器。这个迭代器总是有限大小的,并且应该被完全消费。iter_of
会做出一次选择来决定迭代器的大小,之后元素生成可能会做出更多的选择。
在不使用 exhaustive_test 宏的情况下使用此 crate
任何实现了 Exhaustive
特性的类型都将自动实现以下函数
fn iter_exhaustive(max_choices: Option<usize>) -> impl Iterator<Item=Self>;
此函数提供了一个包含该类型所有生成值的迭代器,可选地带有最大选择数。
与 arbitrary 的比较
arbitrary crate 对此 crate 是一个很大的启发。它提供了与此 crate 相似的功能,但它做出了几个不同的设计决策,使其无法用于高效的穷举测试。
类型总是从一个字节切片中生成,这意味着不可能做出精确的选择,只能读取一个字节并根据它做出选择。这对于 arbitrary
的预期用途来说是可行的,即生成任意值。但要生成所有值进行穷举,这意味着我们可能需要生成所有字节序列,这可能非常大。这最终会导致生成大量重复值,因此扩展性较差。
依赖
~110KB