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()
    }
}