1use std::marker::PhantomData;
4
5use rand::distr::Distribution;
6use rand::{Rng, RngExt};
7use rand_distr::LogNormal;
8
9const BOUNDARIES_U64: &[u64] = &[
16 0,
17 1,
18 i8::MAX as u64 - 1,
19 i8::MAX as u64,
20 i8::MAX as u64 + 1,
21 u8::MAX as u64 - 1,
22 u8::MAX as u64,
23 u8::MAX as u64 + 1,
24 i16::MAX as u64 - 1,
25 i16::MAX as u64,
26 i16::MAX as u64 + 1,
27 u16::MAX as u64 - 1,
28 u16::MAX as u64,
29 u16::MAX as u64 + 1,
30 i32::MAX as u64 - 1,
31 i32::MAX as u64,
32 i32::MAX as u64 + 1,
33 u32::MAX as u64 - 1,
34 u32::MAX as u64,
35 u32::MAX as u64 + 1,
36 i64::MAX as u64 - 1,
37 i64::MAX as u64,
38 i64::MAX as u64 + 1,
39 u64::MAX - 1,
40 u64::MAX,
41];
42
43const BOUNDARIES_I64: &[i64] = &[
45 i64::MIN,
46 i64::MIN + 1,
47 i32::MIN as i64,
48 i16::MIN as i64,
49 i8::MIN as i64,
50 -1,
51 0,
52 1,
53 i8::MAX as i64,
54 i16::MAX as i64,
55 i32::MAX as i64,
56 i64::MAX - 1,
57 i64::MAX,
58];
59
60const BOUNDARIES_F64: &[f64] = &[
63 0.0,
64 1.0,
65 -1.0,
66 f64::MIN_POSITIVE,
67 -f64::MIN_POSITIVE,
68 f64::MAX,
69 f64::MIN,
70];
71
72#[derive(Debug, Clone, Copy)]
77pub struct Probe;
78
79impl Distribution<u64> for Probe {
80 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
81 if rng.random_ratio(1, 8) {
82 BOUNDARIES_U64[rng.random_range(0..BOUNDARIES_U64.len())]
83 } else {
84 typical(rng)
85 }
86 }
87}
88
89impl Distribution<i64> for Probe {
90 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> i64 {
91 if rng.random_ratio(1, 8) {
92 BOUNDARIES_I64[rng.random_range(0..BOUNDARIES_I64.len())]
93 } else {
94 let magnitude = num_traits::cast::<u64, i64>(typical(rng)).unwrap_or(i64::MAX);
95 if rng.random_ratio(1, 2) {
96 -magnitude
97 } else {
98 magnitude
99 }
100 }
101 }
102}
103
104impl Distribution<f64> for Probe {
105 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
106 if rng.random_ratio(1, 8) {
107 BOUNDARIES_F64[rng.random_range(0..BOUNDARIES_F64.len())]
108 } else {
109 let magnitude = num_traits::cast::<u64, f64>(typical(rng)).unwrap_or(f64::MAX);
110 if rng.random_ratio(1, 2) {
111 -magnitude
112 } else {
113 magnitude
114 }
115 }
116 }
117}
118
119fn typical<R: Rng + ?Sized>(rng: &mut R) -> u64 {
131 let dist = LogNormal::new(1024.0_f64.ln(), 4.0).expect("median > 0 and sigma >= 0");
132 num_traits::cast::<f64, u64>(dist.sample(rng).round()).unwrap_or(u64::MAX)
133}
134
135#[derive(Clone, Copy, Debug, Default)]
143pub struct Boundary<T>(PhantomData<T>);
144
145impl<T> Boundary<T> {
146 #[must_use]
148 pub const fn new() -> Self {
149 Boundary(PhantomData)
150 }
151}
152
153const BOUNDARY_U8: &[u8] = &[0, 1, 2, 126, 127, 128, 129, 254, 255];
154
155impl Distribution<u8> for Boundary<u8> {
156 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
157 BOUNDARY_U8[rng.random_range(0..BOUNDARY_U8.len())]
158 }
159}
160
161const BOUNDARY_U64: &[u64] = &[
162 0,
163 1,
164 2,
165 u8::MAX as u64 - 1,
166 u8::MAX as u64,
167 u8::MAX as u64 + 1,
168 u16::MAX as u64 - 1,
169 u16::MAX as u64,
170 u16::MAX as u64 + 1,
171 u32::MAX as u64 - 1,
172 u32::MAX as u64,
173 u32::MAX as u64 + 1,
174 u64::MAX / 2 - 1,
175 u64::MAX / 2,
176 u64::MAX / 2 + 1,
177 u64::MAX - 1,
178 u64::MAX,
179];
180
181impl Distribution<u64> for Boundary<u64> {
182 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
183 BOUNDARY_U64[rng.random_range(0..BOUNDARY_U64.len())]
184 }
185}
186
187const BOUNDARY_I64: &[i64] = &[
188 i64::MIN,
189 i64::MIN + 1,
190 i64::MIN / 2 - 1,
191 i64::MIN / 2,
192 i64::MIN / 2 + 1,
193 i32::MIN as i64,
194 i16::MIN as i64,
195 i8::MIN as i64,
196 -1,
197 0,
198 1,
199 i8::MAX as i64,
200 i16::MAX as i64,
201 i32::MAX as i64,
202 i64::MAX / 2 - 1,
203 i64::MAX / 2,
204 i64::MAX / 2 + 1,
205 i64::MAX - 1,
206 i64::MAX,
207];
208
209impl Distribution<i64> for Boundary<i64> {
210 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> i64 {
211 BOUNDARY_I64[rng.random_range(0..BOUNDARY_I64.len())]
212 }
213}