1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
use crate::{DieOnce, Limit, Prng};
/// Contains parameters for controlling the value generation with [`DieOnce`] and [`Die`].
///
/// The first parameter is a [`Prng`]. It is the only source of randomness that a implementor of
/// [`DieOnce`] or [`Die`] is allowed to use. Using the [`Prng`] will mutate its state, but for
/// the cause of preventing misuse there is no direct write access to it.
///
/// The second parameter is a [`Limit`]. It's the upper limit for the length of dynamic data
/// structures generated by the implementor of `DieOnce` or [`Die`]. The implementor has only read
/// access to the [`Limit`].
///
/// [`Die`]: crate::Die
pub struct Fate<'a> {
prng: &'a mut Prng,
limit: Limit,
}
impl<'a> Fate<'a> {
/// Creates a new instance that uses the given parameters for value generation.
pub fn new(prng: &'a mut Prng, limit: Limit) -> Self {
Self { prng, limit }
}
/// Returns the next pseudorandom number generated with the underlying [`Prng`].
pub fn next_number(&mut self) -> u64 {
self.prng.next_number()
}
/// Returns a [`Prng`] split off from the underlying [`Prng`].
pub fn fork_prng(&mut self) -> Prng {
self.prng.fork()
}
/// Returns the underlying [`Limit`].
pub fn limit(&self) -> Limit {
self.limit
}
/// Creates a borrowed copy.
///
/// [`Fate`] cannot implement the [`Copy`] trait because it contains a mutable
/// reference. When it's necessary to move [`Fate`] multiple times this functions provides a
/// convenient workaround.
///
/// # Example
///
/// ```
/// use dicetest::{Limit, Fate, Prng};
///
/// let mut prng = Prng::from_seed(42.into());
/// let limit = Limit::default();
/// let mut fate = Fate::new(&mut prng, limit);
///
/// pub fn take_fate(_fate: Fate) {}
///
/// take_fate(fate.copy());
/// take_fate(fate);
/// ```
pub fn copy(&mut self) -> Fate {
Fate {
prng: self.prng,
limit: self.limit,
}
}
/// Creates a copy with the given limit.
pub fn with_limit(&mut self, limit: Limit) -> Fate {
let mut fate = self.copy();
fate.limit = limit;
fate
}
/// Generates a value with the given [`DieOnce`] using `self` as parameter.
///
/// This function is more convenient than calling [`DieOnce::roll_once`] directly because
/// it borrows the [`Fate`] instead of moving it.
///
/// ```
/// use dicetest::prelude::*;
/// use dicetest::{Limit, Prng};
///
/// let mut prng = Prng::from_seed(42.into());
/// let limit = Limit::default();
/// let mut fate = Fate::new(&mut prng, limit);
///
/// let die = dice::bool();
///
/// let val1 = fate.roll(&die); // Borrows `fate`
/// let val2 = die.roll(fate); // Moves `fate`
/// ```
pub fn roll<T, D: DieOnce<T>>(&mut self, die: D) -> T {
die.roll_once(self.copy())
}
/// Generates a value using the given [`Distribution`].
///
/// Only available if the feature `rand_full` is enabled.
///
/// [`Distribution`]: rand::distributions::Distribution
#[cfg(any(feature = "rand_full", all(feature = "rand_core", feature = "rand")))]
pub fn roll_distribution<T, D>(&mut self, distribution: D) -> T
where
D: rand::distributions::Distribution<T>,
{
let die = crate::dice::from_distribution(distribution);
self.roll(die)
}
/// Generates a value of a type that implements [`Arbitrary`].
///
/// Only available if the feature `quickcheck_full` is enabled.
///
/// [`Arbitrary`]: quickcheck::Arbitrary
#[cfg(any(
feature = "quickcheck_full",
all(feature = "rand_core", feature = "quickcheck")
))]
pub fn roll_arbitrary<T>(&mut self) -> T
where
T: quickcheck::Arbitrary,
{
T::arbitrary(self)
}
}
#[cfg(feature = "rand_core")]
impl<'a> rand_core::RngCore for Fate<'a> {
fn next_u32(&mut self) -> u32 {
self.next_number() as u32
}
fn next_u64(&mut self) -> u64 {
self.next_number()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
rand_core::impls::fill_bytes_via_next(self, dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
self.fill_bytes(dest);
Ok(())
}
}
#[cfg(any(
feature = "quickcheck_full",
all(feature = "rand_core", feature = "quickcheck")
))]
impl<'a> quickcheck::Gen for Fate<'a> {
fn size(&self) -> usize {
self.limit.saturating_to_usize()
}
}