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.
33pub use generate_random_macro::GenerateRandom;
34
35/// Enable randomly generating values of a type.
36///
37/// This trait can be implemented using the derive
38/// macro of the same name: [`macro@GenerateRandom`].
39pub trait GenerateRandom {
40    /// Create a new random value of this type.
41    fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self;
42}
43
44macro_rules! impl_generate_random {
45    ( $( $t:ty, )+ ) => {
46        $(
47            impl GenerateRandom for $t {
48                fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
49                    rng.gen()
50                }
51            }
52        )+
53    }
54}
55
56impl_generate_random! {
57    bool,
58    char,
59    u8,
60    i8,
61    u16,
62    i16,
63    u32,
64    i32,
65    u64,
66    i64,
67    u128,
68    i128,
69    usize,
70    isize,
71    f32,
72    f64,
73}
74
75impl<T: GenerateRandom> GenerateRandom for Option<T> {
76    fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
77        if bool::generate_random(rng) {
78            Some(T::generate_random(rng))
79        } else {
80            None
81        }
82    }
83}
84
85macro_rules! impl_generate_random_tuple {
86    ( $t0:ident $( $t:ident )* ) => {
87        impl< $t0, $( $t, )* > GenerateRandom for ( $t0, $( $t, )* )
88        where
89            $t0: GenerateRandom,
90            $(
91                $t: GenerateRandom,
92            )*
93        {
94            fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
95                (
96                    $t0::generate_random(rng),
97                    $(
98                        $t::generate_random(rng),
99                    )*
100                )
101            }
102        }
103        impl_generate_random_tuple!( $( $t )* );
104    };
105    () => {
106        impl GenerateRandom for () {
107            fn generate_random<R: rand::Rng + ?Sized>(_rng: &mut R) -> Self {
108                ()
109            }
110        }
111    }
112}
113
114impl_generate_random_tuple!(A B C D E F G H I J K L);
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    fn rng() -> impl rand::Rng {
121        use rand::SeedableRng;
122        rand_chacha::ChaCha8Rng::from(rand_chacha::ChaCha8Core::from_seed([37; 32]))
123    }
124
125    #[test]
126    fn test_u8() {
127        let mut rng = rng();
128        assert_eq!(u8::generate_random(&mut rng), 55);
129    }
130}