]> git.lizzy.rs Git - generate-random.git/blobdiff - lib/src/lib.rs
Add support for Ranges
[generate-random.git] / lib / src / lib.rs
index 67432e306d6bd02bda0394214e276fc87299a527..d8ec04f22eaec2c58650387d7837b628fec8d646 100644 (file)
@@ -41,6 +41,22 @@ pub trait GenerateRandom {
     fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self;
 }
 
+/// Enable randomly generating values of an enum
+/// with a predefined variant
+///
+/// This trait is automatically implemented for enums
+/// by the [`macro@GenerateRandom`] macro
+pub trait GenerateRandomVariant {
+    /// Return number of variants
+    fn num_variants() -> usize;
+
+    /// Return name of variant with index
+    fn variant_name(variant: usize) -> &'static str;
+
+    /// Create a randomly generated value with a predefied variant
+    fn generate_random_variant<R: rand::Rng + ?Sized>(rng: &mut R, variant: usize) -> Self;
+}
+
 macro_rules! impl_generate_random {
        ( $( $t:ty, )+ ) => {
                $(
@@ -84,18 +100,7 @@ impl<T: GenerateRandom> GenerateRandom for Option<T> {
 
 impl<T: GenerateRandom, const N: usize> GenerateRandom for [T; N] {
     fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
-        use core::mem::MaybeUninit;
-
-        let mut arr: [MaybeUninit<T>; 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
+        core::array::from_fn(|_| T::generate_random(rng))
     }
 }
 
@@ -108,6 +113,87 @@ impl GenerateRandom for String {
     }
 }
 
+impl<T: GenerateRandom> GenerateRandom for Vec<T> {
+    fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
+        let len = rng.gen_range(0..8);
+        (0..len).map(|_| T::generate_random(rng)).collect()
+    }
+}
+
+impl<T> GenerateRandom for std::collections::HashSet<T>
+where
+    T: GenerateRandom + std::cmp::Eq + std::hash::Hash,
+{
+    fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
+        let len = rng.gen_range(0..8);
+        (0..len).map(|_| T::generate_random(rng)).collect()
+    }
+}
+
+impl<K, V> GenerateRandom for std::collections::HashMap<K, V>
+where
+    K: GenerateRandom + std::cmp::Eq + std::hash::Hash,
+    V: GenerateRandom,
+{
+    fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
+        let len = rng.gen_range(0..8);
+        (0..len)
+            .map(|_| (K::generate_random(rng), V::generate_random(rng)))
+            .collect()
+    }
+}
+
+impl<T: GenerateRandom> GenerateRandom for Box<T> {
+    fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
+        Box::new(T::generate_random(rng))
+    }
+}
+
+impl<T: GenerateRandom> GenerateRandom for std::ops::Range<T> {
+    fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
+        T::generate_random(rng)..T::generate_random(rng)
+    }
+}
+
+impl<T: GenerateRandom> GenerateRandom for std::ops::RangeFrom<T> {
+    fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
+        T::generate_random(rng)..
+    }
+}
+
+impl GenerateRandom for std::ops::RangeFull {
+    fn generate_random<R: rand::Rng + ?Sized>(_rng: &mut R) -> Self {
+        ..
+    }
+}
+
+impl<T: GenerateRandom> GenerateRandom for std::ops::RangeInclusive<T> {
+    fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
+        T::generate_random(rng)..=T::generate_random(rng)
+    }
+}
+
+impl<T: GenerateRandom> GenerateRandom for std::ops::RangeTo<T> {
+    fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
+        ..T::generate_random(rng)
+    }
+}
+impl<T: GenerateRandom> GenerateRandom for std::ops::RangeToInclusive<T> {
+    fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
+        ..=T::generate_random(rng)
+    }
+}
+
+#[cfg(feature = "enumset")]
+impl<T: enumset::EnumSetType + GenerateRandom> GenerateRandom for enumset::EnumSet<T> {
+    fn generate_random<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
+        let max = enumset::EnumSet::<T>::variant_count() * 2;
+        let len = rng.gen_range(0..max);
+
+        (0..len).map(|_| T::generate_random(rng)).collect()
+    }
+}
+
 macro_rules! impl_generate_random_tuple {
        ( $t0:ident $( $t:ident )* ) => {
                impl< $t0, $( $t, )* > GenerateRandom for ( $t0, $( $t, )* )