Skip to main content

autorand/
lib.rs

1pub use autorand_derive::Random;
2pub use rand;
3
4use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, LinkedList, VecDeque};
5use std::hash::{BuildHasher, Hash};
6
7use rand::{distributions::Alphanumeric, Rng};
8
9const LEN_LIMIT: usize = 16;
10
11const UINT_LIMIT: usize = u16::max_value() as usize;
12const INT_LOWER_LIMIT: isize = 0 - (UINT_LIMIT as isize);
13const INT_UPPER_LIMIT: isize = UINT_LIMIT as isize;
14
15pub trait Random: Sized {
16    fn random() -> Self;
17}
18
19impl<T: Random> Random for Option<T> {
20    fn random() -> Self {
21        if rand::random::<bool>() {
22            Some(T::random())
23        } else {
24            None
25        }
26    }
27}
28
29impl Random for String {
30    fn random() -> Self {
31        let mut rng = rand::thread_rng();
32        let length = rng.gen_range(0, LEN_LIMIT);
33        rng.sample_iter(&Alphanumeric).take(length).collect()
34    }
35}
36
37impl<T: Random> Random for Vec<T> {
38    fn random() -> Self {
39        rand_length_iter().collect()
40    }
41}
42
43impl<K: Random + Eq + Hash, V: Random, S: BuildHasher + Default> Random for HashMap<K, V, S> {
44    fn random() -> Self {
45        rand_length_iter::<(K, V)>().collect()
46    }
47}
48
49impl<K: Random + Ord, V: Random> Random for BTreeMap<K, V> {
50    fn random() -> Self {
51        rand_length_iter::<(K, V)>().collect()
52    }
53}
54
55impl<T: Random + Eq + Hash, S: BuildHasher + Default> Random for HashSet<T, S> {
56    fn random() -> Self {
57        rand_length_iter().collect()
58    }
59}
60
61impl<T: Random + Ord> Random for BTreeSet<T> {
62    fn random() -> Self {
63        rand_length_iter().collect()
64    }
65}
66
67impl<T: Random> Random for VecDeque<T> {
68    fn random() -> Self {
69        rand_length_iter().collect()
70    }
71}
72
73impl<T: Random> Random for LinkedList<T> {
74    fn random() -> Self {
75        rand_length_iter().collect()
76    }
77}
78
79fn rand_length_iter<T: Random>() -> impl Iterator<Item = T> {
80    let length = rand::thread_rng().gen_range(0, LEN_LIMIT);
81    rand_iter().take(length)
82}
83
84fn rand_iter<T: Random>() -> impl Iterator<Item = T> {
85    (0..).map(|_| T::random())
86}
87
88impl Random for f32 {
89    fn random() -> Self {
90        let base = rand::random::<f32>();
91        (base * 1000.0).ceil() / 1000.0
92    }
93}
94
95impl Random for f64 {
96    fn random() -> Self {
97        let base = rand::random::<f64>();
98        (base * 1000.0).ceil() / 1000.0
99    }
100}
101
102macro_rules! impl_primitives_unsigned {
103    ($($t:tt,)*) => {
104        $(
105        impl Random for $t {
106            fn random() -> Self {
107                let mut rng = rand::thread_rng();
108                if cfg!(not(feature = "limited-integers")) || ($t::max_value() as usize) < UINT_LIMIT {
109                    rng.gen_range(0, $t::max_value())
110                } else {
111                    rng.gen_range(0, UINT_LIMIT as $t)
112                }
113            }
114        }
115        )*
116    };
117}
118
119macro_rules! impl_primitives_signed {
120    ($($t:tt,)*) => {
121        $(
122        impl Random for $t {
123            fn random() -> Self {
124                let mut rng = rand::thread_rng();
125                if cfg!(not(feature = "limited-integers")) || ($t::max_value() as isize) < INT_UPPER_LIMIT {
126                    rng.gen_range($t::min_value(), $t::max_value())
127                } else {
128                    rng.gen_range(INT_LOWER_LIMIT as $t, INT_UPPER_LIMIT as $t)
129                }
130            }
131        }
132        )*
133    };
134}
135
136#[rustfmt::skip]
137impl_primitives_signed! {
138    i8, i16, i32, i64, isize,
139}
140
141impl_primitives_unsigned! {
142    u8, u16, u32, u64, usize,
143}
144
145impl Random for char {
146    fn random() -> Self {
147        rand::random()
148    }
149}
150
151impl Random for bool {
152    fn random() -> Self {
153        rand::random()
154    }
155}
156
157macro_rules! impl_arrays {
158    ($($s:expr,)*) => {
159        $(
160        impl<T: Random> Random for [T; $s] {
161            fn random() -> Self {
162                use std::mem::{MaybeUninit, transmute_copy, size_of};
163                unsafe {
164                    let mut array: [MaybeUninit<T>; $s] = MaybeUninit::uninit().assume_init();
165                    for elem in &mut array[..] {
166                        *elem = MaybeUninit::new(T::random());
167                    }
168
169                    // See https://github.com/rust-lang/rust/issues/47966
170                    debug_assert!(size_of::<[MaybeUninit<T>; $s]>() == size_of::<[T; $s]>());
171                    transmute_copy::<_, [T; $s]>(&array)
172                }
173            }
174        }
175        )*
176    };
177}
178
179#[rustfmt::skip]
180impl_arrays!(
181    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
182    17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 32,
183    64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384,
184);
185
186macro_rules! impl_tuples {
187    ($([$($t:tt)*],)*) => {
188        $(
189        impl<$($t:Random,)*> Random for ($($t,)*) {
190            fn random() -> Self {
191                ($($t::random(),)*)
192            }
193        }
194        )*
195    };
196}
197
198impl_tuples!(
199    [A],
200    [A B],
201    [A B C],
202    [A B C D],
203    [A B C D E],
204    [A B C D E F],
205    [A B C D E F G],
206    [A B C D E F G H],
207    [A B C D E F G H I],
208    [A B C D E F G H I J],
209    [A B C D E F G H I J K],
210);
211
212#[cfg(feature = "json")]
213impl Random for serde_json::Map<String, serde_json::Value> {
214    fn random() -> Self {
215        rand_length_iter().collect()
216    }
217}
218
219#[cfg(feature = "json")]
220impl Random for serde_json::Number {
221    fn random() -> Self {
222        serde_json::Number::from_f64(Random::random()).unwrap()
223    }
224}
225
226#[cfg(feature = "json")]
227#[cfg(not(feature = "json-value-always-null"))]
228impl Random for serde_json::Value {
229    fn random() -> Self {
230        use serde_json::Value;
231        let variant = rand::thread_rng().gen_range(0u8, 6);
232        match variant {
233            0 => Value::Number(Random::random()),
234            1 => Value::Bool(Random::random()),
235            2 => Value::String(Random::random()),
236            3 => Value::Array(Random::random()),
237            4 => Value::Null,
238            5 => Value::Object(Random::random()),
239            _ => unreachable!(),
240        }
241    }
242}
243
244#[cfg(feature = "json")]
245#[cfg(feature = "json-value-always-null")]
246impl Random for serde_json::Value {
247    fn random() -> Self {
248        use serde_json::Value;
249        Value::Null
250    }
251}