Arbitrary Trait
The Arbitrary
trait is the foundation for generating non-deterministic values in Kani proof harnesses. It allows you to create symbolic values that represent all possible values of a given type.
For a type to implement Arbitrary
, Kani must be able to represent every possible value of it, so unbounded types cannot implement it. For nondeterministic representations of unbounded types, e.g., Vec
, see the BoundedArbitrary
trait.
Overview
The Arbitrary
trait defines methods for generating arbitrary (nondeterministic) values:
pub trait Arbitrary
where
Self: Sized,
{
fn any() -> Self;
fn any_array<const MAX_ARRAY_LENGTH: usize>() -> [Self; MAX_ARRAY_LENGTH] {
[(); MAX_ARRAY_LENGTH].map(|_| Self::any())
}
}
Basic Usage
Use kani::any()
to generate arbitrary values in proof harnesses:
#[kani::proof]
fn verify_function() {
let x: u32 = kani::any();
let y: bool = kani::any();
let z: [char; 10] = kani::any();
// x represents all possible u32 values
// y represents both true and false
// z represents an array of length 10 where each element can hold all possible char values
my_function(x, y, z);
}
Kani implements Arbitrary
for primitive types and some standard library types. See the crate trait documentation for a full list of implementations.
Constrained Values
Use any_where
or kani::assume()
to add constraints to arbitrary values:
#[kani::proof]
fn verify_with_constraints() {
let x: u32 = kani::any_where(|t| *t < 1000); // Constrain x to be less than 1000
kani::assume(x % 2 == 0); // Constrain x to be even
// Now x represents all even numbers from 0 to 998
my_function(x);
}
# Derive Implementations
Kani can automatically derive `Arbitrary` implementations for structs and enums when all their fields/variants implement `Arbitrary`:
## Structs
```rust
#[derive(kani::Arbitrary)]
struct Point {
x: i32,
y: i32,
}
#[kani::proof]
fn verify_point() {
let point: Point = kani::any();
// point.x and point.y can be any i32 values
process_point(point);
}
Enums
#[derive(kani::Arbitrary)]
enum Status {
Ready,
Processing(u32),
Error { code: (char, i32) },
}
#[kani::proof]
fn verify_status() {
let status: Status = kani::any();
// `status` can be any of the variants
match status {
Status::Ready => { /* ... */ }
Status::Processing(id) => { /* id can be any u32 */ }
Status::Error { code } => { /* code can be any (char, i32) tuple */ }
}
}
Manual Implementations
Implement Arbitrary
manually when you need constraints or custom logic. For example, Kani manually implements Arbitrary
for NonZero
types to exclude zero values, e.g:
impl Arbitrary for NonZeroU8 {
fn any() -> Self {
let val = u8::any();
kani::assume(val != 0);
unsafe { NonZeroU8::new_unchecked(val) }
}
}
An alternative means to add value constraints is provided by the Invariant trait.