sample-std 0.1.0

Sampler definitions and implementations for st
Documentation

Core sampling strategies, along with useful implementations for samplers on types from [std] and the [quickcheck] crate.

The core of this library is the [Sample] trait, which uses [Random] to generate arbitrary values from a sampled Output type with a custom "sampling strategy". It also defines a procedure for "shrinking" generated values, which can be used to generate simple counterexamples against expected properties.

This library is generally intended for usage alongside the sample_test crate. See that crate for macros and examples for using samplers within unit tests.

Sampling Strategies

The simplest [Sample] implementation is for [Range]. It is a sampler that generates values uniformly from the given range, and attempts to shrink down to the start of the range:

use sample_std::{Sample, Random};

let s = 10..100;
let v = s.generate(&mut Random::new());
assert!(s.contains(&v));
let mut shrunk = s.shrink(v);
assert_eq!(shrunk.next(), Some(s.start));
if v > s.start {
assert!(shrunk.next().unwrap() < v)
}

Samplers are defined for tuples of samplers up to size 8, which can be used in concert with [Sample::try_convert] to combine samplers into a sampler for a larger type:

use sample_std::{Chance, Sample, VecSampler, choice};

struct Large {
values: Vec<usize>,
is_blue: bool,
name: String,
}

let sampler = (
VecSampler { length: 0..10, el: 5..20 },
Chance(0.5),
choice(["cora".to_string(), "james".to_string()])
).try_convert(
|(values, is_blue, name)| Large { values, is_blue, name },
|large| Some((large.values, large.is_blue, large.name))
);

For an example of sampling an enum, see [sampler_choice].

Prior Work

This crate is heavily inspired by [quickcheck]. It builds upon it, in particular by defining samplers for [Arbitrary] (see [arbitrary]). Many methods and structs in here were derived from their [quickcheck] counterparts.

It attempts to iterate and improve on the [quickcheck] core idea:

  • Allow definition of multiple sampling strategies for the same type.
  • No need to define newtypes for custom sampling strategies.

There is still some cruft and weirdness from this early attempt to combine these worldviews:

  • The concept of size isn't really necessary in a world with sampling strategies.
  • The [Random] struct could probably just become a type definition around the underlying rng.

The core idea for sampling "strategies" comes from proptest, which uses macros instead of combinators for composition, and has more complex shrinking functionality.