//! Generate random data. //! //! # Examples //! //! ``` //! use generate_random::GenerateRandom; //! //! #[derive(GenerateRandom)] //! enum MyEnum { //! A, //! C(bool), //! B { //! x: u8, //! }, //! // Providing a weight allows changing the probabilities. //! // This variant is now twice as likely to be generated as the others. //! #[weight(2)] //! D, //! } //! //! let mut rng = rand::thread_rng(); //! let my_value = MyEnum::generate_random(&mut rng); //! ``` /// This derive macro provides an implementation /// of the [`trait@GenerateRandom`] trait. /// /// Enum variants can be given a `weight` attribute /// to change how often it is generated. /// By default, the weight is `1`. /// The probability of a variants is its weight /// divided by the sum over all variants. pub use generate_random_macro::GenerateRandom; /// Enable randomly generating values of a type. /// /// This trait can be implemented using the derive /// macro of the same name: [`macro@GenerateRandom`]. pub trait GenerateRandom { /// Create a new random value of this type. fn generate_random(rng: &mut R) -> Self; } macro_rules! impl_generate_random { ( $( $t:ty, )+ ) => { $( impl GenerateRandom for $t { fn generate_random(rng: &mut R) -> Self { rng.gen() } } )+ } } impl_generate_random! { bool, char, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64, } impl GenerateRandom for Option { fn generate_random(rng: &mut R) -> Self { if bool::generate_random(rng) { Some(T::generate_random(rng)) } else { None } } } impl GenerateRandom for [T; N] { fn generate_random(rng: &mut R) -> Self { use core::mem::MaybeUninit; let mut arr: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; for elem in arr.iter_mut() { *elem = MaybeUninit::new(T::generate_random(rng)); } let ret = unsafe { std::mem::transmute_copy(&arr) }; std::mem::forget(arr); ret } } macro_rules! impl_generate_random_tuple { ( $t0:ident $( $t:ident )* ) => { impl< $t0, $( $t, )* > GenerateRandom for ( $t0, $( $t, )* ) where $t0: GenerateRandom, $( $t: GenerateRandom, )* { fn generate_random(rng: &mut R) -> Self { ( $t0::generate_random(rng), $( $t::generate_random(rng), )* ) } } impl_generate_random_tuple!( $( $t )* ); }; () => { impl GenerateRandom for () { fn generate_random(_rng: &mut R) -> Self { () } } } } impl_generate_random_tuple!(A B C D E F G H I J K L); #[cfg(test)] mod tests { use super::*; fn rng() -> impl rand::Rng { use rand::SeedableRng; rand_chacha::ChaCha8Rng::from(rand_chacha::ChaCha8Core::from_seed([37; 32])) } #[test] fn test_u8() { let mut rng = rng(); assert_eq!(u8::generate_random(&mut rng), 55); } }