1use crate::Rng;
2use core::ops::{Bound, RangeBounds};
3
4macro_rules! gen {
5 ($($type:ty),+) => {
6 $(
7 impl<Generator: Rng<OUTPUT>, const OUTPUT: usize> RandomGen<Generator, OUTPUT> for $type {
8 fn random(rng: &mut Generator) -> Self {
9 let mut bytes = [0u8; core::mem::size_of::<$type>()];
10 rng.fill_bytes(&mut bytes);
11 Self::from_ne_bytes(bytes)
12 }
13 }
14 )+
15 };
16}
17
18macro_rules! range {
19 ($(($type:ty, $bigger:ty, $signed:ty)),+) => {
20 $(
21 impl<Generator: Rng<OUTPUT>, const OUTPUT: usize> RandomRange<Generator, OUTPUT> for $type {
22 fn random_range<Bounds: RangeBounds<Self>>(rng: &mut Generator, bounds: Bounds) -> Self {
23 const BITS: $bigger = core::mem::size_of::<$type>() as $bigger * 8;
24 let lower = match bounds.start_bound() {
25 Bound::Included(lower) => *lower,
26 Bound::Excluded(lower) => lower.saturating_add(1),
27 Bound::Unbounded => <$type>::MIN,
28 };
29 let upper = match bounds.end_bound() {
30 Bound::Included(upper) => upper.saturating_add(1),
31 Bound::Excluded(upper) => *upper,
32 Bound::Unbounded => <$type>::MAX,
33 };
34 assert!(upper >= lower, "{} >= {} (lower bound was bigger than upper bound)", upper, lower);
35 let upper = upper.saturating_sub(lower);
36 let mut value = Self::random(rng);
37 let mut m = (upper as $bigger).wrapping_mul(value as $bigger);
38 if (m as $type) < upper {
39 let t = (!upper + 1) % upper;
40 while (m as $type) < t {
41 value = Self::random(rng);
42 m = (upper as $bigger).wrapping_mul(value as $bigger);
43 }
44 }
45 (m >> BITS) as $type + lower
46 }
47 }
48
49 impl<Generator: Rng<OUTPUT>, const OUTPUT: usize> RandomRange<Generator, OUTPUT> for $signed {
50 fn random_range<Bounds: RangeBounds<Self>>(r: &mut Generator, bounds: Bounds) -> Self {
51 let lower = match bounds.start_bound() {
52 Bound::Included(lower) => *lower,
53 Bound::Excluded(lower) => lower.saturating_add(1),
54 Bound::Unbounded => <$signed>::MIN
55 };
56 let upper = match bounds.end_bound() {
57 Bound::Included(upper) => *upper,
58 Bound::Excluded(upper) => upper.saturating_sub(1),
59 Bound::Unbounded => <$signed>::MAX,
60 };
61 assert!(upper >= lower, "{} >= {} (lower bound was bigger than upper bound)", upper, lower);
62 let lower = lower.wrapping_sub(<$signed>::MIN) as $type;
63 let upper = upper.wrapping_sub(<$signed>::MIN) as $type;
64 <$type>::random_range(r, lower..=upper).wrapping_add(<$signed>::MAX as $type) as $signed
65 }
66 }
67 )+
68 }
69}
70
71pub trait RandomGen<Generator: Rng<OUTPUT>, const OUTPUT: usize> {
73 fn random(rng: &mut Generator) -> Self;
75}
76
77pub trait RandomRange<Generator: Rng<OUTPUT>, const OUTPUT: usize>:
79 RandomGen<Generator, OUTPUT>
80{
81 fn random_range<Bounds: RangeBounds<Self>>(nng: &mut Generator, range: Bounds) -> Self;
86}
87
88impl<Generator: Rng<OUTPUT>, const OUTPUT: usize> RandomGen<Generator, OUTPUT> for bool {
89 fn random(rng: &mut Generator) -> Self {
90 u8::random(rng) < 0b10000000
91 }
92}
93
94impl<Generator: Rng<OUTPUT>, const OUTPUT: usize> RandomGen<Generator, OUTPUT> for f32 {
95 fn random(rng: &mut Generator) -> Self {
96 (u32::random(rng) as f32) / (u32::MAX as f32)
97 }
98}
99
100impl<Generator: Rng<OUTPUT>, const OUTPUT: usize> RandomGen<Generator, OUTPUT> for f64 {
101 fn random(rng: &mut Generator) -> Self {
102 (u64::random(rng) as f64) / (u64::MAX as f64)
103 }
104}
105
106gen!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
107range!(
108 (u8, u16, i8),
109 (u16, u32, i16),
110 (u32, u64, i32),
111 (u64, u128, i64)
112);
113#[cfg(target_pointer_width = "16")]
114range!((usize, u32, isize));
115#[cfg(target_pointer_width = "32")]
116range!((usize, u64, isize));
117#[cfg(target_pointer_width = "64")]
118range!((usize, u128, isize));
119
120#[cfg(test)]
121mod tests {
122 use crate::{Rng, WyRand};
123 #[test]
124 fn ensure_unsigned_in_range() {
125 let mut rng = WyRand::new();
126 for _ in 0..1000 {
127 let number = rng.generate_range(10_u64..=20);
128 assert!(
129 (10..=20).contains(&number),
130 "{} was outside of 10..=20",
131 number
132 );
133
134 let number = rng.generate_range(10_u64..30);
135 assert!(
136 (10..30).contains(&number),
137 "{} was outside of 10..30",
138 number
139 );
140
141 let number = rng.generate_range(512_u64..);
142 assert!((512..).contains(&number), "{} was outside of 512..", number);
143
144 let number = rng.generate_range(..1024_u64);
145 assert!(
146 (..1024).contains(&number),
147 "{} was outside of ..1024",
148 number
149 );
150 }
151 }
152 #[test]
153 fn ensure_signed_in_range() {
154 let mut rng = WyRand::new();
155 for _ in 0..1000 {
156 let number = rng.generate_range(-50..);
157 assert!((-50..).contains(&number), "{} was outside of -50..", number);
158
159 let number = rng.generate_range(..512);
160 assert!((..512).contains(&number), "{} was outside of ..512", number);
161
162 let number = rng.generate_range(..-32);
163 assert!((..-32).contains(&number), "{} was outside of ..-32", number);
164 }
165 }
166
167 #[test]
168 fn ensure_floats_generate_properly() {
169 let mut rng = WyRand::new();
170 for _ in 0..1000 {
171 let number = rng.generate::<f32>();
172 assert!(1.0 >= number, "{} was bigger than 1.0", number);
173 assert!(number >= 0.0, "0 was bigger than {}", number);
174
175 let number = rng.generate::<f64>();
176 assert!(1.0 >= number, "{} was bigger than 1.0", number);
177 assert!(number >= 0.0, "0 was bigger than {}", number);
178 }
179 }
180
181 #[test]
182 #[should_panic]
183 fn ensure_invalid_range_panics() {
184 let mut rng = WyRand::new();
185 #[allow(clippy::reversed_empty_ranges)]
186 rng.generate_range(10..=5);
187 }
188}