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
use crate::die::adapters::{ArcDie, BoxedDie, FlatMapDie, FlattenDie, MapDie, RcDie};
use crate::die::{DieOnce, Fate, Limit};
use crate::prand::{Prng, Seed};

/// Trait for generating preudorandom values of type `T`.
///
/// The `Die` trait represents a subset of `DieOnce`. It mirrors all methods of `DieOnce` without
/// the suffix `_once`. These methods must behave in the same way. For example an implementation
/// of `Die` must produce the same value with its methods `roll` and `roll_once` if they are called
/// with the same `Fate`.
pub trait Die<T>: DieOnce<T> {
    /// Generates a preudorandom value.
    ///
    /// The `Fate` is the only source of the randomness. Besides that, the generation is
    /// derterministic.
    fn roll(&self, fate: &mut Fate) -> T;

    /// Creates a new `Die` by mapping the generated values of `self`.
    ///
    /// The function `f` will be applied to the generated values of `self`. These function results
    /// are the generated values of the new `Die`.
    fn map<U, F>(self, f: F) -> MapDie<T, U, Self, F>
    where
        Self: Sized,
        F: Fn(T) -> U,
    {
        MapDie::new(self, f)
    }

    /// Creates a new `Die` whose values are generated by the generated `Die`s of `self`.
    fn flatten<U>(self) -> FlattenDie<U, T, Self>
    where
        Self: Sized,
        T: DieOnce<U>,
    {
        FlattenDie::new(self)
    }

    /// Creates a new `Die` similiar to `Die::map`, except that the mapping produces `DieOnce`s.
    ///
    /// The function `f` will be applied to the generated values of `self`. These function results
    /// are `DieOnce`s that generates the values for the new `Die`.
    ///
    /// It is semanticly equivalent to `self.map(f).flatten()`.
    fn flat_map<U, UD, F>(self, f: F) -> FlatMapDie<T, U, Self, UD, F>
    where
        Self: Sized,
        UD: DieOnce<U>,
        F: Fn(T) -> UD,
    {
        FlatMapDie::new(self, f)
    }

    /// Puts `self` behind a `Box` pointer.
    fn boxed<'a>(self) -> BoxedDie<'a, T>
    where
        Self: Sized + 'a,
    {
        BoxedDie::new(self)
    }

    /// Puts `self` behind an `Rc` pointer.
    fn rc<'a>(self) -> RcDie<'a, T>
    where
        Self: Sized + 'a,
    {
        RcDie::new(self)
    }

    /// Puts `self` behind an `Arc` pointer.
    fn arc(self) -> ArcDie<T>
    where
        Self: Sized + 'static,
    {
        ArcDie::new(self)
    }

    /// Calls `roll` with random `Seed` and default `Limit`. Useful for debugging the
    /// generator.
    fn sample(&self) -> T {
        self.sample_with_limit(Limit::default())
    }

    /// Calls `roll` with random `Seed` and the given `Limit`. Useful for debugging the
    /// generator.
    fn sample_with_limit(&self, limit: Limit) -> T {
        let mut prng = Prng::from_seed(Seed::random());
        let mut fate = Fate::new(&mut prng, limit);

        self.roll(&mut fate)
    }
}