# DieOnce and Die

Although [`Prng`] can only generate pseudorandom `u64`s, the `u64`s can be used for constructing
more complex values. The traits [`DieOnce`] and [`Die`] represent [`Prng`]-based generators for
values of any type.

An implementor of [`DieOnce`] is a generator that can be used a single time
(similar to [`FnOnce`]).

```rust
use dicetest::prelude::*;

let xx = "xx".to_string();
let yy = "yy".to_string();

// This generator implements `DieOnce`.
// It chooses one of the `String`s without cloning them.
let xx_or_yy_die = dice::one_of_once().two(xx, yy);
```

An implementor of [`Die`] is a generator that can be used an infinite number of
times (similar to [`Fn`]).

```rust
use dicetest::prelude::*;

let xx = "xx".to_string();
let yy = "yy".to_string();

// This generator implements `Die`.
// It chooses one of the `String`s by cloning them.
let xx_or_yy_die = dice::one_of().two(xx, yy);

// This generator uses `xx_or_yy_die` to generate three `String`s at once.
let three_xx_or_yy_die = dice::array::<_, _, 3>(xx_or_yy_die);
```

Generators can be easily implemented and composed:

```rust
use dicetest::prelude::*;

// A classic die that generates a number between 1 and 6 with uniform distribution.
let classic_die = dice::one_of().six::<u8>(1, 2, 3, 4, 5, 6);

// A loaded die that generates the number 6 more frequently.
let loaded_die =
    dice::weighted_one_of().six::<u8>((1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 6));

// This die generates the result of the function.
let die_from_fn = dice::from_fn(|_| 42);

// This die generates always the same `String` by cloning the original one.
let foo_die = dice::just("foo".to_string());

// This die generates an arbitrary byte.
let byte_die = dice::u8(..);

// This die generates a non-zero byte.
let non_zero_byte_die = dice::u8(1..);

// This die generates a `Vec` that contains an arbitrary number of arbitrary bytes.
let bytes_die = dice::vec(dice::u8(..), ..);

// This die generates a `Vec` that contains up to 10 arbitrary bytes.
let up_to_ten_bytes_die = dice::vec(dice::u8(..), ..=10);

// This die generates an arbitrary wrapped byte.
struct WrappedByte(u8);
let wrapped_byte_die = dice::u8(..).map(WrappedByte);

// This die generates a permutation of `(0..=n)` for an arbitrary `n`.
let permutation_die = dice::length(0..).flat_map(|n| {
    let vec = (0..=n).collect::<Vec<_>>();
    dice::shuffled_vec(vec)
});
```

The struct [`Fate`] is necessary for using [`DieOnce`] or [`Die`]. It contains two parameters:

- [`Prng`]: Provides the pseudorandom `u64`s that the implementor of [`DieOnce`] or [`Die`] can use
  for constructing more complex values. The implementor should only use this as its source of
  randomness.
- [`Limit`]: The upper limit for the length of dynamic data structures generated by the
  implementor of [`DieOnce`] or [`Die`]. The implementor is allowed to freely interpret or even
  ignore this value.

```rust
use dicetest::prelude::*;
use dicetest::{Limit, Prng};

// Provides the randomness for the generator and will be mutated when used.
let mut prng = Prng::from_seed(0x5EED.into());
// Limits the length of dynamic data structures. The generator has only read access.
let limit = Limit(5);

// Contains all parameters necessary for using `DieOnce` or `Die`.
let mut fate = Fate::new(&mut prng, limit);

// Generator for a `Vec` with an arbitrary length.
let vec_die = dice::vec(dice::u8(..), ..);

// Generates a `Vec`. Although `vec_die` can generate a `Vec` with an arbitrary length,
// the length of the actual `Vec` is limited by `limit`.
let vec = fate.roll(vec_die);
assert!(vec.len() <= 5);

println!("{:?}", vec);
// Output: [252, 231, 153, 0]
```

[`DieOnce`]: https://docs.rs/dicetest/latest/dicetest/trait.DieOnce.html
[`Die`]: https://docs.rs/dicetest/latest/dicetest/trait.Die.html
[`Fate`]: https://docs.rs/dicetest/latest/dicetest/struct.Fate.html
[`FnOnce`]: https://doc.rust-lang.org/std/ops/trait.FnOnce.html
[`Fn`]: https://doc.rust-lang.org/std/ops/trait.Fn.html
[`Limit`]: https://docs.rs/dicetest/latest/dicetest/struct.Limit.html
[`Prng`]: https://docs.rs/dicetest/latest/dicetest/struct.Prng.html
