1use super::{Error, SampleBorrow, SampleUniform, Uniform, UniformInt, UniformSampler};
13use crate::distr::Distribution;
14use crate::Rng;
15use core::time::Duration;
16
17#[cfg(feature = "serde")]
18use serde::{Deserialize, Serialize};
19
20impl SampleUniform for char {
21 type Sampler = UniformChar;
22}
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
34#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
35pub struct UniformChar {
36 #[cfg_attr(feature = "serde", serde(deserialize_with = "deser_sampler"))]
37 sampler: UniformInt<u32>,
38}
39
40#[cfg(feature = "serde")]
41fn deser_sampler<'de, D>(d: D) -> Result<UniformInt<u32>, D::Error>
42where
43 D: serde::Deserializer<'de>,
44{
45 let sampler = <UniformInt<u32> as serde::Deserialize>::deserialize(d)?;
46 if sampler.max() > char::MAX as u32 - CHAR_SURROGATE_LEN {
47 return Err(serde::de::Error::custom(
48 "bad sampler range for UniformChar",
49 ));
50 }
51 Ok(sampler)
52}
53
54const CHAR_SURROGATE_START: u32 = 0xD800;
56const CHAR_SURROGATE_LEN: u32 = 0xE000 - CHAR_SURROGATE_START;
58
59fn char_to_comp_u32(c: char) -> u32 {
61 match c as u32 {
62 c if c >= CHAR_SURROGATE_START => c - CHAR_SURROGATE_LEN,
63 c => c,
64 }
65}
66
67impl UniformSampler for UniformChar {
68 type X = char;
69
70 #[inline] fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
73 where
74 B1: SampleBorrow<Self::X> + Sized,
75 B2: SampleBorrow<Self::X> + Sized,
76 {
77 let low = char_to_comp_u32(*low_b.borrow());
78 let high = char_to_comp_u32(*high_b.borrow());
79 let sampler = UniformInt::<u32>::new(low, high);
80 sampler.map(|sampler| UniformChar { sampler })
81 }
82
83 #[inline] fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
86 where
87 B1: SampleBorrow<Self::X> + Sized,
88 B2: SampleBorrow<Self::X> + Sized,
89 {
90 let low = char_to_comp_u32(*low_b.borrow());
91 let high = char_to_comp_u32(*high_b.borrow());
92 let sampler = UniformInt::<u32>::new_inclusive(low, high);
93 sampler.map(|sampler| UniformChar { sampler })
94 }
95
96 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
97 let mut x = self.sampler.sample(rng);
98 if x >= CHAR_SURROGATE_START {
99 x += CHAR_SURROGATE_LEN;
100 }
101 unsafe { core::char::from_u32_unchecked(x) }
105 }
106}
107
108#[cfg(feature = "alloc")]
109impl crate::distr::SampleString for Uniform<char> {
110 fn append_string<R: Rng + ?Sized>(
111 &self,
112 rng: &mut R,
113 string: &mut alloc::string::String,
114 len: usize,
115 ) {
116 let mut hi = self.0.sampler.low + self.0.sampler.range - 1;
118 if hi >= CHAR_SURROGATE_START {
119 hi += CHAR_SURROGATE_LEN;
120 }
121 let max_char_len = char::from_u32(hi).map(char::len_utf8).unwrap_or(4);
123 string.reserve(max_char_len * len);
124 string.extend(self.sample_iter(rng).take(len))
125 }
126}
127
128#[derive(Clone, Copy, Debug, PartialEq, Eq)]
133#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
134pub struct UniformDuration {
135 mode: UniformDurationMode,
136 offset: u32,
137}
138
139#[derive(Debug, Copy, Clone, PartialEq, Eq)]
140#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
141enum UniformDurationMode {
142 Small {
143 secs: u64,
144 nanos: Uniform<u32>,
145 },
146 Medium {
147 nanos: Uniform<u64>,
148 },
149 Large {
150 max_secs: u64,
151 max_nanos: u32,
152 secs: Uniform<u64>,
153 },
154}
155
156impl SampleUniform for Duration {
157 type Sampler = UniformDuration;
158}
159
160impl UniformSampler for UniformDuration {
161 type X = Duration;
162
163 #[inline]
164 fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
165 where
166 B1: SampleBorrow<Self::X> + Sized,
167 B2: SampleBorrow<Self::X> + Sized,
168 {
169 let low = *low_b.borrow();
170 let high = *high_b.borrow();
171 if !(low < high) {
172 return Err(Error::EmptyRange);
173 }
174 UniformDuration::new_inclusive(low, high - Duration::new(0, 1))
175 }
176
177 #[inline]
178 fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
179 where
180 B1: SampleBorrow<Self::X> + Sized,
181 B2: SampleBorrow<Self::X> + Sized,
182 {
183 let low = *low_b.borrow();
184 let high = *high_b.borrow();
185 if !(low <= high) {
186 return Err(Error::EmptyRange);
187 }
188
189 let low_s = low.as_secs();
190 let low_n = low.subsec_nanos();
191 let mut high_s = high.as_secs();
192 let mut high_n = high.subsec_nanos();
193
194 if high_n < low_n {
195 high_s -= 1;
196 high_n += 1_000_000_000;
197 }
198
199 let mode = if low_s == high_s {
200 UniformDurationMode::Small {
201 secs: low_s,
202 nanos: Uniform::new_inclusive(low_n, high_n)?,
203 }
204 } else {
205 let max = high_s
206 .checked_mul(1_000_000_000)
207 .and_then(|n| n.checked_add(u64::from(high_n)));
208
209 if let Some(higher_bound) = max {
210 let lower_bound = low_s * 1_000_000_000 + u64::from(low_n);
211 UniformDurationMode::Medium {
212 nanos: Uniform::new_inclusive(lower_bound, higher_bound)?,
213 }
214 } else {
215 let max_nanos = high_n - low_n;
217 UniformDurationMode::Large {
218 max_secs: high_s,
219 max_nanos,
220 secs: Uniform::new_inclusive(low_s, high_s)?,
221 }
222 }
223 };
224 Ok(UniformDuration {
225 mode,
226 offset: low_n,
227 })
228 }
229
230 #[inline]
231 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Duration {
232 match self.mode {
233 UniformDurationMode::Small { secs, nanos } => {
234 let n = nanos.sample(rng);
235 Duration::new(secs, n)
236 }
237 UniformDurationMode::Medium { nanos } => {
238 let nanos = nanos.sample(rng);
239 Duration::new(nanos / 1_000_000_000, (nanos % 1_000_000_000) as u32)
240 }
241 UniformDurationMode::Large {
242 max_secs,
243 max_nanos,
244 secs,
245 } => {
246 let nano_range = Uniform::new(0, 1_000_000_000).unwrap();
248 loop {
249 let s = secs.sample(rng);
250 let n = nano_range.sample(rng);
251 if !(s == max_secs && n > max_nanos) {
252 let sum = n + self.offset;
253 break Duration::new(s, sum);
254 }
255 }
256 }
257 }
258 }
259}
260
261#[cfg(test)]
262mod tests {
263 use super::*;
264
265 #[test]
266 #[cfg(feature = "serde")]
267 fn test_serialization_uniform_duration() {
268 let distr = UniformDuration::new(Duration::from_secs(10), Duration::from_secs(60)).unwrap();
269 let de_distr: UniformDuration =
270 bincode::deserialize(&bincode::serialize(&distr).unwrap()).unwrap();
271 assert_eq!(distr, de_distr);
272 }
273
274 #[test]
275 #[cfg_attr(miri, ignore)] fn test_char() {
277 let mut rng = crate::test::rng(891);
278 let mut max = core::char::from_u32(0).unwrap();
279 for _ in 0..100 {
280 let c = rng.random_range('A'..='Z');
281 assert!(c.is_ascii_uppercase());
282 max = max.max(c);
283 }
284 assert_eq!(max, 'Z');
285 let d = Uniform::new(
286 core::char::from_u32(0xD7F0).unwrap(),
287 core::char::from_u32(0xE010).unwrap(),
288 )
289 .unwrap();
290 for _ in 0..100 {
291 let c = d.sample(&mut rng);
292 assert!((c as u32) < 0xD800 || (c as u32) > 0xDFFF);
293 }
294 #[cfg(feature = "alloc")]
295 {
296 use crate::distr::SampleString;
297 let string1 = d.sample_string(&mut rng, 100);
298 assert_eq!(string1.capacity(), 300);
299 let string2 = Uniform::new(
300 core::char::from_u32(0x0000).unwrap(),
301 core::char::from_u32(0x0080).unwrap(),
302 )
303 .unwrap()
304 .sample_string(&mut rng, 100);
305 assert_eq!(string2.capacity(), 100);
306 let string3 = Uniform::new_inclusive(
307 core::char::from_u32(0x0000).unwrap(),
308 core::char::from_u32(0x0080).unwrap(),
309 )
310 .unwrap()
311 .sample_string(&mut rng, 100);
312 assert_eq!(string3.capacity(), 200);
313 }
314 }
315
316 #[test]
317 #[cfg(feature = "serde")]
318 fn test_char_bad_deser() {
319 let json = r#"{"sampler":{"low":4294967200,"range":0,"thresh":0}}"#;
320 let result = serde_json::from_str::<Uniform<char>>(json);
321 assert!(result.is_err());
322 let err = result.unwrap_err();
323 assert_eq!(err.classify(), serde_json::error::Category::Data);
324
325 #[cfg(feature = "alloc")]
326 {
327 assert_eq!(
328 alloc::string::ToString::to_string(&err),
329 "bad sampler range for UniformChar at line 1 column 51"
330 );
331 }
332 }
333
334 #[test]
335 #[cfg_attr(miri, ignore)] fn test_durations() {
337 let mut rng = crate::test::rng(253);
338
339 let v = &[
340 (Duration::new(10, 50000), Duration::new(100, 1234)),
341 (Duration::new(0, 100), Duration::new(1, 50)),
342 (Duration::new(0, 0), Duration::new(u64::MAX, 999_999_999)),
343 ];
344 for &(low, high) in v.iter() {
345 let my_uniform = Uniform::new(low, high).unwrap();
346 for _ in 0..1000 {
347 let v = rng.sample(my_uniform);
348 assert!(low <= v && v < high);
349 }
350 }
351 }
352}