Skip to main content

generate_random/
lib.rs

1//! Generate random data.
2//!
3//! # Examples
4//!
5//! ```
6//! use generate_random::GenerateRandom;
7//!
8//! #[derive(GenerateRandom)]
9//! enum MyEnum {
10//!     A,
11//!     C(bool),
12//!     B {
13//!         x: u8,
14//!     },
15//!     // Providing a weight allows changing the probabilities.
16//!     // This variant is now twice as likely to be generated as the others.
17//!     #[weight(2)]
18//!     D,
19//! }
20//!
21//! let mut rng = rand::thread_rng();
22//! let my_value = MyEnum::generate_random(&mut rng);
23//! ```
24
25/// This derive macro provides an implementation
26/// of the [`trait@GenerateRandom`] trait.
27///
28/// Enum variants can be given a `weight` attribute
29/// to change how often it is generated.
30/// By default, the weight is `1`.
31/// The probability of a variants is its weight
32/// divided by the sum over all variants.
33#[cfg(feature = "derive")]
34pub use generate_random_macro::GenerateRandom;
35
36pub use rand::Rng;
37
38/// Generate a random value for a type.
39pub fn generate<T, R>(rng: &mut R) -> T
40where
41    T: GenerateRandom,
42    R: Rng,
43{
44    GenerateRandom::generate_random(rng)
45}
46
47/// Enable randomly generating values of a type.
48///
49/// This trait can be implemented using the derive
50/// macro of the same name: [`macro@GenerateRandom`].
51pub trait GenerateRandom {
52    /// Create a new random value of this type.
53    fn generate_random<R: Rng + ?Sized>(rng: &mut R) -> Self;
54}
55
56macro_rules! impl_generate_random {
57    ( $( $t:ty, )+ ) => {
58        $(
59            impl GenerateRandom for $t {
60                fn generate_random<R: Rng + ?Sized>(rng: &mut R) -> Self {
61                    rng.gen()
62                }
63            }
64        )+
65    }
66}
67
68impl_generate_random! {
69    bool,
70    char,
71    u8,
72    i8,
73    u16,
74    i16,
75    u32,
76    i32,
77    u64,
78    i64,
79    u128,
80    i128,
81    usize,
82    isize,
83    f32,
84    f64,
85}
86
87impl<T: GenerateRandom> GenerateRandom for Option<T> {
88    fn generate_random<R: Rng + ?Sized>(rng: &mut R) -> Self {
89        if bool::generate_random(rng) {
90            Some(T::generate_random(rng))
91        } else {
92            None
93        }
94    }
95}
96
97macro_rules! impl_generate_random_tuple {
98    ( $t0:ident $( $t:ident )* ) => {
99        impl< $t0, $( $t, )* > GenerateRandom for ( $t0, $( $t, )* )
100        where
101            $t0: GenerateRandom,
102            $(
103                $t: GenerateRandom,
104            )*
105        {
106            fn generate_random<R: Rng + ?Sized>(rng: &mut R) -> Self {
107                (
108                    $t0::generate_random(rng),
109                    $(
110                        $t::generate_random(rng),
111                    )*
112                )
113            }
114        }
115        impl_generate_random_tuple!( $( $t )* );
116    };
117    () => {
118        impl GenerateRandom for () {
119            fn generate_random<R: Rng + ?Sized>(_rng: &mut R) -> Self {
120                ()
121            }
122        }
123    }
124}
125
126impl_generate_random_tuple!(A B C D E F G H I J K L);
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131
132    fn rng() -> impl rand::Rng {
133        use rand::SeedableRng;
134        rand_chacha::ChaCha8Rng::from(rand_chacha::ChaCha8Core::from_seed([37; 32]))
135    }
136
137    #[test]
138    fn test_u8() {
139        let mut rng = rng();
140        assert_eq!(u8::generate_random(&mut rng), 55);
141    }
142}