1#[cfg(feature = "derive")]
34pub use generate_random_macro::GenerateRandom;
35
36pub use rand::{Rng, RngExt};
37
38pub fn generate<T, R>(rng: &mut R) -> T
40where
41 T: GenerateRandom,
42 R: Rng + ?Sized,
43{
44 GenerateRandom::generate_random(rng)
45}
46
47pub trait GenerateRandom {
52 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 rand::RngExt::random(rng)
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 f32,
82 f64,
83}
84
85impl GenerateRandom for usize {
86 fn generate_random<R: Rng + ?Sized>(rng: &mut R) -> Self {
87 cfg_select! {
88 target_pointer_width = "16" => u16::generate_random(rng) as usize,
89 target_pointer_width = "32" => u32::generate_random(rng) as usize,
90 target_pointer_width = "64" => u64::generate_random(rng) as usize,
91 }
92 }
93}
94
95impl GenerateRandom for isize {
96 fn generate_random<R: Rng + ?Sized>(rng: &mut R) -> Self {
97 cfg_select! {
98 target_pointer_width = "16" => i16::generate_random(rng) as isize,
99 target_pointer_width = "32" => i32::generate_random(rng) as isize,
100 target_pointer_width = "64" => i64::generate_random(rng) as isize,
101 }
102 }
103}
104
105impl<T: GenerateRandom> GenerateRandom for Option<T> {
106 fn generate_random<R: Rng + ?Sized>(rng: &mut R) -> Self {
107 if bool::generate_random(rng) {
108 Some(T::generate_random(rng))
109 } else {
110 None
111 }
112 }
113}
114
115macro_rules! impl_generate_random_tuple {
116 ( $t0:ident $( $t:ident )* ) => {
117 impl< $t0, $( $t, )* > GenerateRandom for ( $t0, $( $t, )* )
118 where
119 $t0: GenerateRandom,
120 $(
121 $t: GenerateRandom,
122 )*
123 {
124 fn generate_random<R: Rng + ?Sized>(rng: &mut R) -> Self {
125 (
126 $t0::generate_random(rng),
127 $(
128 $t::generate_random(rng),
129 )*
130 )
131 }
132 }
133 impl_generate_random_tuple!( $( $t )* );
134 };
135 () => {
136 impl GenerateRandom for () {
137 fn generate_random<R: Rng + ?Sized>(_rng: &mut R) -> Self {
138 ()
139 }
140 }
141 }
142}
143
144impl_generate_random_tuple!(A B C D E F G H I J K L);
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149
150 fn rng() -> impl rand::Rng {
151 use rand::SeedableRng;
152 rand_chacha::ChaCha8Rng::from(rand_chacha::ChaCha8Core::from_seed([37; 32]))
153 }
154
155 #[test]
156 fn test_u8() {
157 let mut rng = rng();
158 assert_eq!(u8::generate_random(&mut rng), 55);
159 }
160}