You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Mention #[derive(Arbitrary)] and bolero_engine::TypeGenerator in our tutorial (rust-lang#2060)
Expand the section "Custom nondeterministic types" to include the new derive macro and the bolero TypeGenerator trait.
Co-authored-by: Zyad Hassan <[email protected]>
Copy file name to clipboardExpand all lines: docs/src/tutorial-nondeterministic-variables.md
+32-13Lines changed: 32 additions & 13 deletions
Original file line number
Diff line number
Diff line change
@@ -41,26 +41,45 @@ The assertion we wrote in this harness was just an extra check we added to demon
41
41
42
42
## Custom nondeterministic types
43
43
44
-
While `kani::any()` is the only method Kani provides to inject non-determinism into a proof harness, Kani only ships with implementations for a few types where we can guarantee safety.
45
-
When you need nondeterministic variables of types that `kani::any()` cannot construct, you have two options:
46
-
47
-
1. Implement the `kani::Arbitrary` trait for your type, so you can use `kani::any()`.
48
-
2. Just write a function.
49
-
50
-
The advantage of the first approach is that it's simple and conventional.
51
-
It also means that in addition to being able to use `kani::any()` with your type, you can also use it with `Option<MyType>` (for example).
52
-
53
-
The advantage of the second approach is that you're able to pass in parameters, like bounds on the size of the data structure.
44
+
While `kani::any()` is the only method Kani provides to inject non-determinism into a proof harness, Kani only ships with implementations for a few `std` types where we can guarantee safety.
45
+
When you need nondeterministic variables of types that don't have a `kani::any()` implementation available, you have the following options:
46
+
47
+
1. Implement the `kani::Arbitrary` trait for your type, so you and downstream crates can use `kani::any()` with your type.
48
+
2. Implement the [`bolero_generator::TypeGenerator` trait](https://docs.rs/bolero-generator/0.8.0/bolero_generator/trait.TypeGenerator.html).
49
+
This will enable you and downstream crates to use Kani via [Bolero](https://camshaft.github.io/bolero/).
50
+
3. Write a function that builds an object from non-deterministic variables.
51
+
52
+
We recommend the first approach for most cases.
53
+
The first approach is simple and conventional. This option will also enable you to use it with parameterized types, such as `Option<MyType>` and arrays.
54
+
Kani includes a derive macro that allows you to automatically derive `kani::Arbitrary` for structures and enumerations as long as all its fields also implement the `kani::Arbitrary` trait.
55
+
One downside of this approach today is that the `kani` crate ships with Kani, but it's not yet available on [crates.io](https://crates.io).
56
+
So you need to annotate the Arbitrary implementation with a `#[cfg(kani)]` attribute.
57
+
For the derive macro, use `#[cfg_attr(kani, derive(kani::Arbitrary))]`.
58
+
59
+
The second approach is recommended for cases where you would also like to be able to apply fuzzing or property testing.
60
+
The benefits of doing so were described in [this blog post](https://model-checking.github.io/kani-verifier-blog/2022/10/27/using-kani-with-the-bolero-property-testing-framework.html).
61
+
Like `kani::Arbitrary`, this trait can also be used with a `derive` macro.
62
+
One thing to be aware of is that this type allow users to generate arbitrary values that include pointers.
63
+
In those cases, **only the values pointed to are arbitrary**, not the pointers themselves.
64
+
65
+
Finally, the last approach is recommended when you need to pass in parameters, like bounds on the size of the data structure.
54
66
(Which we'll discuss more in the next section.)
55
-
This approach is also necessary when you are unable to implement a trait (like `Arbitrary`) on a type you're importing from another crate.
67
+
This approach is also necessary when you need to generate a nondeterministic variable of a type that you're importing from another crate, since Rust doesn't allow you to implement a trait defined in an external crate for a type that you don't own.
56
68
57
69
Either way, inside this function you would simply return an arbitrary value by generating arbitrary values for its components.
58
70
To generate a nondeterministic struct, you would just generate nondeterministic values for each of its fields.
59
71
For complex data structures like vectors or other containers, you can start with an empty one and add a (bounded) nondeterministic number of entries.
60
-
For an enum, you can make use of a simple trick:
72
+
73
+
For example, for a simple enum you can just annotate it with the Arbitrary derive attribute:
0 commit comments