1use super::{Error, SampleBorrow, SampleUniform, Uniform, UniformInt, UniformSampler};
13use crate::Rng;
14use crate::distr::Distribution;
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
102 char::from_u32(x)
103 .expect("rand::distr::uniform::UniformChar: invalid Unicode scalar value (likely memory corruption)")
104 }
105}
106
107#[cfg(feature = "alloc")]
108impl crate::distr::SampleString for Uniform<char> {
109 fn append_string<R: Rng + ?Sized>(
110 &self,
111 rng: &mut R,
112 string: &mut alloc::string::String,
113 len: usize,
114 ) {
115 let mut hi = self.0.sampler.low + self.0.sampler.range - 1;
117 if hi >= CHAR_SURROGATE_START {
118 hi += CHAR_SURROGATE_LEN;
119 }
120 let max_char_len = char::from_u32(hi).map(char::len_utf8).unwrap_or(4);
122 string.reserve(max_char_len * len);
123 string.extend(self.sample_iter(rng).take(len))
124 }
125}
126
127#[derive(Clone, Copy, Debug, PartialEq, Eq)]
132#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
133pub struct UniformDuration {
134 mode: UniformDurationMode,
135 offset: u32,
136}
137
138#[derive(Debug, Copy, Clone, PartialEq, Eq)]
139#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
140enum UniformDurationMode {
141 Small {
142 secs: u64,
143 nanos: Uniform<u32>,
144 },
145 Medium {
146 nanos: Uniform<u64>,
147 },
148 Large {
149 max_secs: u64,
150 max_nanos: u32,
151 secs: Uniform<u64>,
152 },
153}
154
155impl SampleUniform for Duration {
156 type Sampler = UniformDuration;
157}
158
159impl UniformSampler for UniformDuration {
160 type X = Duration;
161
162 #[inline]
163 fn new<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
164 where
165 B1: SampleBorrow<Self::X> + Sized,
166 B2: SampleBorrow<Self::X> + Sized,
167 {
168 let low = *low_b.borrow();
169 let high = *high_b.borrow();
170 if !(low < high) {
171 return Err(Error::EmptyRange);
172 }
173 UniformDuration::new_inclusive(low, high - Duration::new(0, 1))
174 }
175
176 #[inline]
177 fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Result<Self, Error>
178 where
179 B1: SampleBorrow<Self::X> + Sized,
180 B2: SampleBorrow<Self::X> + Sized,
181 {
182 let low = *low_b.borrow();
183 let high = *high_b.borrow();
184 if !(low <= high) {
185 return Err(Error::EmptyRange);
186 }
187
188 let low_s = low.as_secs();
189 let low_n = low.subsec_nanos();
190 let mut high_s = high.as_secs();
191 let mut high_n = high.subsec_nanos();
192
193 if high_n < low_n {
194 high_s -= 1;
195 high_n += 1_000_000_000;
196 }
197
198 let mode = if low_s == high_s {
199 UniformDurationMode::Small {
200 secs: low_s,
201 nanos: Uniform::new_inclusive(low_n, high_n)?,
202 }
203 } else {
204 let max = high_s
205 .checked_mul(1_000_000_000)
206 .and_then(|n| n.checked_add(u64::from(high_n)));
207
208 if let Some(higher_bound) = max {
209 let lower_bound = low_s * 1_000_000_000 + u64::from(low_n);
210 UniformDurationMode::Medium {
211 nanos: Uniform::new_inclusive(lower_bound, higher_bound)?,
212 }
213 } else {
214 let max_nanos = high_n - low_n;
216 UniformDurationMode::Large {
217 max_secs: high_s,
218 max_nanos,
219 secs: Uniform::new_inclusive(low_s, high_s)?,
220 }
221 }
222 };
223 Ok(UniformDuration {
224 mode,
225 offset: low_n,
226 })
227 }
228
229 #[inline]
230 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Duration {
231 match self.mode {
232 UniformDurationMode::Small { secs, nanos } => {
233 let n = nanos.sample(rng);
234 Duration::new(secs, n)
235 }
236 UniformDurationMode::Medium { nanos } => {
237 let nanos = nanos.sample(rng);
238 Duration::new(nanos / 1_000_000_000, (nanos % 1_000_000_000) as u32)
239 }
240 UniformDurationMode::Large {
241 max_secs,
242 max_nanos,
243 secs,
244 } => {
245 let nano_range = Uniform::new(0, 1_000_000_000).unwrap();
247 loop {
248 let s = secs.sample(rng);
249 let n = nano_range.sample(rng);
250 if !(s == max_secs && n > max_nanos) {
251 let sum = n + self.offset;
252 break Duration::new(s, sum);
253 }
254 }
255 }
256 }
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263 use crate::RngExt;
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 postcard::from_bytes(&postcard::to_allocvec(&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}