1 //! Generate random data.
6 //! use generate_random::GenerateRandom;
8 //! #[derive(GenerateRandom)]
15 //! // Providing a weight allows changing the probabilities.
16 //! // This variant is now twice as likely to be generated as the others.
21 //! let mut rng = rand::thread_rng();
22 //! let my_value = MyEnum::generate_random(&mut rng);
25 /// This derive macro provides an implementation
26 /// of the [`trait@GenerateRandom`] trait.
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 pub use generate_random_macro::GenerateRandom;
35 /// Enable randomly generating values of a type.
37 /// This trait can be implemented using the derive
38 /// macro of the same name: [`macro@GenerateRandom`].
39 pub trait GenerateRandom {
40 /// Create a new random value of this type.
41 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self;
44 /// Enable randomly generating values of an enum
45 /// with a predefined variant
47 /// This trait is automatically implemented for enums
48 /// by the [`macro@GenerateRandom`] macro
49 pub trait GenerateRandomVariant {
50 /// Return number of variants
51 fn num_variants() -> usize;
53 /// Return name of variant with index
54 fn variant_name(variant: usize) -> &'static str;
56 /// Create a randomly generated value with a predefied variant
57 fn generate_random_variant<R: rand::Rng + ?Sized>(rng: &mut R, variant: usize) -> Self;
60 macro_rules! impl_generate_random {
63 impl GenerateRandom for $t {
64 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
72 impl_generate_random! {
91 impl<T: GenerateRandom> GenerateRandom for Option<T> {
92 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
93 if bool::generate_random(rng) {
94 Some(T::generate_random(rng))
101 impl<T: GenerateRandom, const N: usize> GenerateRandom for [T; N] {
102 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
103 core::array::from_fn(|_| T::generate_random(rng))
107 impl GenerateRandom for String {
108 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
109 use rand::distributions::{Alphanumeric, DistString};
111 let len = rng.gen_range(0..32);
112 Alphanumeric.sample_string(rng, len)
116 impl<T: GenerateRandom> GenerateRandom for Vec<T> {
117 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
118 let len = rng.gen_range(0..8);
119 (0..len).map(|_| T::generate_random(rng)).collect()
123 impl<T> GenerateRandom for std::collections::HashSet<T>
125 T: GenerateRandom + std::cmp::Eq + std::hash::Hash,
127 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
128 let len = rng.gen_range(0..8);
129 (0..len).map(|_| T::generate_random(rng)).collect()
133 impl<K, V> GenerateRandom for std::collections::HashMap<K, V>
135 K: GenerateRandom + std::cmp::Eq + std::hash::Hash,
138 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
139 let len = rng.gen_range(0..8);
141 .map(|_| (K::generate_random(rng), V::generate_random(rng)))
146 impl<T: GenerateRandom> GenerateRandom for Box<T> {
147 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
148 Box::new(T::generate_random(rng))
152 impl<T: GenerateRandom> GenerateRandom for std::ops::Range<T> {
153 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
154 T::generate_random(rng)..T::generate_random(rng)
158 impl<T: GenerateRandom> GenerateRandom for std::ops::RangeFrom<T> {
159 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
160 T::generate_random(rng)..
164 impl GenerateRandom for std::ops::RangeFull {
165 fn generate_random<R: rand::Rng + ?Sized>(_rng: &mut R) -> Self {
170 impl<T: GenerateRandom> GenerateRandom for std::ops::RangeInclusive<T> {
171 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
172 T::generate_random(rng)..=T::generate_random(rng)
176 impl<T: GenerateRandom> GenerateRandom for std::ops::RangeTo<T> {
177 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
178 ..T::generate_random(rng)
181 impl<T: GenerateRandom> GenerateRandom for std::ops::RangeToInclusive<T> {
182 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
183 ..=T::generate_random(rng)
187 #[cfg(feature = "enumset")]
188 impl<T: enumset::EnumSetType + GenerateRandom> GenerateRandom for enumset::EnumSet<T> {
189 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
190 let max = enumset::EnumSet::<T>::variant_count() * 2;
191 let len = rng.gen_range(0..max);
193 (0..len).map(|_| T::generate_random(rng)).collect()
197 macro_rules! impl_generate_random_tuple {
198 ( $t0:ident $( $t:ident )* ) => {
199 impl< $t0, $( $t, )* > GenerateRandom for ( $t0, $( $t, )* )
206 fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
208 $t0::generate_random(rng),
210 $t::generate_random(rng),
215 impl_generate_random_tuple!( $( $t )* );
218 #[allow(clippy::unused_unit)]
219 impl GenerateRandom for () {
220 fn generate_random<R: rand::Rng + ?Sized>(_rng: &mut R) -> Self {
227 impl_generate_random_tuple!(A B C D E F G H I J K L);
233 fn rng() -> impl rand::Rng {
234 use rand::SeedableRng;
235 rand_chacha::ChaCha8Rng::from(rand_chacha::ChaCha8Core::from_seed([37; 32]))
241 assert_eq!(u8::generate_random(&mut rng), 55);