musli_tests/models/
generate.rs

1#[cfg(feature = "std")]
2use core::hash::Hash;
3use core::ops::Range;
4
5use alloc::ffi::CString;
6use alloc::string::String;
7use alloc::vec::Vec;
8
9use rand::distributions::Distribution;
10use rand::distributions::Standard;
11
12#[cfg(feature = "std")]
13use std::collections::HashMap;
14
15miri! {
16    const STRING_RANGE: Range<usize> = 0..256, 0..16;
17    #[cfg(feature = "std")]
18    const MAP_RANGE: Range<usize> = 10..100, 1..3;
19    const VEC_RANGE: Range<usize> = 10..100, 1..3;
20}
21
22pub trait Generate: Sized {
23    /// Generate a value of the given type.
24    fn generate<R>(rng: &mut R) -> Self
25    where
26        R: rand::Rng;
27
28    /// Implement to receive a range parameters, by default it is simply ignored.
29    fn generate_range<R>(rng: &mut R, _: Range<usize>) -> Self
30    where
31        R: rand::Rng,
32    {
33        Self::generate(rng)
34    }
35}
36
37impl<T> Generate for Vec<T>
38where
39    T: Generate,
40{
41    #[inline]
42    fn generate<R>(rng: &mut R) -> Self
43    where
44        R: rand::Rng,
45    {
46        <Vec<T> as Generate>::generate_range(rng, VEC_RANGE)
47    }
48
49    fn generate_range<R>(rng: &mut R, range: Range<usize>) -> Self
50    where
51        R: rand::Rng,
52    {
53        let cap = rng.gen_range(range);
54        let mut vec = Vec::with_capacity(cap);
55
56        for _ in 0..cap {
57            vec.push(T::generate(rng));
58        }
59
60        vec
61    }
62}
63
64#[cfg(feature = "std")]
65impl<K, V> Generate for HashMap<K, V>
66where
67    K: Eq + Hash,
68    K: Generate,
69    V: Generate,
70{
71    #[inline]
72    fn generate<T>(rng: &mut T) -> Self
73    where
74        T: rand::Rng,
75    {
76        Self::generate_range(rng, MAP_RANGE)
77    }
78
79    fn generate_range<T>(rng: &mut T, range: Range<usize>) -> Self
80    where
81        T: rand::Rng,
82    {
83        let cap = rng.gen_range(range);
84        let mut map = HashMap::with_capacity(cap);
85
86        for _ in 0..cap {
87            map.insert(K::generate(rng), V::generate(rng));
88        }
89
90        map
91    }
92}
93
94impl Generate for String {
95    fn generate<T>(rng: &mut T) -> Self
96    where
97        T: rand::Rng,
98    {
99        let mut string = String::new();
100
101        for _ in 0..rng.gen_range(STRING_RANGE) {
102            string.push(rng.gen());
103        }
104
105        string
106    }
107}
108
109impl Generate for CString {
110    fn generate<T>(rng: &mut T) -> Self
111    where
112        T: rand::Rng,
113    {
114        let mut string = Vec::new();
115
116        for _ in 0..rng.gen_range(STRING_RANGE) {
117            string.push(rng.gen_range(1..=u8::MAX));
118        }
119
120        string.push(0);
121        CString::from_vec_with_nul(string).unwrap()
122    }
123}
124
125impl Generate for () {
126    #[inline]
127    fn generate<T>(_: &mut T) -> Self
128    where
129        T: rand::Rng,
130    {
131    }
132}
133
134macro_rules! tuple {
135    ($($ty:ident),* $(,)?) => {
136        impl<$($ty,)*> Generate for ($($ty,)*) where $($ty: Generate,)* {
137            #[inline]
138            fn generate<T>(rng: &mut T) -> Self where T: rand::Rng {
139                ($(<$ty>::generate(rng),)*)
140            }
141        }
142    }
143}
144
145tuple!(A);
146tuple!(A, B);
147tuple!(A, B, C);
148tuple!(A, B, C, D);
149tuple!(A, B, C, D, E);
150tuple!(A, B, C, D, E, F);
151tuple!(A, B, C, D, E, F, G);
152
153macro_rules! primitive {
154    ($ty:ty) => {
155        impl Generate for $ty
156        where
157            Standard: Distribution<$ty>,
158        {
159            #[inline]
160            fn generate<T>(rng: &mut T) -> Self
161            where
162                T: rand::Rng,
163            {
164                rng.gen()
165            }
166        }
167    };
168}
169
170primitive!(u8);
171primitive!(u16);
172primitive!(u32);
173primitive!(u64);
174primitive!(u128);
175primitive!(i8);
176primitive!(i16);
177primitive!(i32);
178primitive!(i64);
179primitive!(i128);
180primitive!(usize);
181primitive!(isize);
182primitive!(f32);
183primitive!(f64);
184primitive!(char);
185primitive!(bool);