Skip to main content

rand/distr/
uniform_other.rs

1// Copyright 2018-2020 Developers of the Rand project.
2// Copyright 2017 The Rust Project Developers.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10//! `UniformChar`, `UniformDuration` implementations
11
12use 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/// The back-end implementing [`UniformSampler`] for `char`.
25///
26/// Unless you are implementing [`UniformSampler`] for your own type, this type
27/// should not be used directly, use [`Uniform`] instead.
28///
29/// This differs from integer range sampling since the range `0xD800..=0xDFFF`
30/// are used for surrogate pairs in UCS and UTF-16, and consequently are not
31/// valid Unicode code points. We must therefore avoid sampling values in this
32/// range.
33#[derive(#[automatically_derived]
impl ::core::clone::Clone for UniformChar {
    #[inline]
    fn clone(&self) -> UniformChar {
        let _: ::core::clone::AssertParamIsClone<UniformInt<u32>>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for UniformChar { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for UniformChar {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f, "UniformChar",
            "sampler", &&self.sampler)
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for UniformChar {
    #[inline]
    fn eq(&self, other: &UniformChar) -> bool {
        self.sampler == other.sampler
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for UniformChar {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<UniformInt<u32>>;
    }
}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
54/// UTF-16 surrogate range start
55const CHAR_SURROGATE_START: u32 = 0xD800;
56/// UTF-16 surrogate range size
57const CHAR_SURROGATE_LEN: u32 = 0xE000 - CHAR_SURROGATE_START;
58
59/// Convert `char` to compressed `u32`
60fn 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] // if the range is constant, this helps LLVM to do the
71    // calculations at compile-time.
72    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] // if the range is constant, this helps LLVM to do the
84    // calculations at compile-time.
85    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        // Getting the hi value to assume the required length to reserve in string.
116        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        // Get the utf8 length of hi to minimize extra space.
121        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/// The back-end implementing [`UniformSampler`] for `Duration`.
128///
129/// Unless you are implementing [`UniformSampler`] for your own types, this type
130/// should not be used directly, use [`Uniform`] instead.
131#[derive(#[automatically_derived]
impl ::core::clone::Clone for UniformDuration {
    #[inline]
    fn clone(&self) -> UniformDuration {
        let _: ::core::clone::AssertParamIsClone<UniformDurationMode>;
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for UniformDuration { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for UniformDuration {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "UniformDuration", "mode", &self.mode, "offset", &&self.offset)
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for UniformDuration {
    #[inline]
    fn eq(&self, other: &UniformDuration) -> bool {
        self.offset == other.offset && self.mode == other.mode
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for UniformDuration {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<UniformDurationMode>;
        let _: ::core::cmp::AssertParamIsEq<u32>;
    }
}Eq)]
132#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
133pub struct UniformDuration {
134    mode: UniformDurationMode,
135    offset: u32,
136}
137
138#[derive(#[automatically_derived]
impl ::core::fmt::Debug for UniformDurationMode {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            UniformDurationMode::Small { secs: __self_0, nanos: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f, "Small",
                    "secs", __self_0, "nanos", &__self_1),
            UniformDurationMode::Medium { nanos: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "Medium", "nanos", &__self_0),
            UniformDurationMode::Large {
                max_secs: __self_0, max_nanos: __self_1, secs: __self_2 } =>
                ::core::fmt::Formatter::debug_struct_field3_finish(f, "Large",
                    "max_secs", __self_0, "max_nanos", __self_1, "secs",
                    &__self_2),
        }
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for UniformDurationMode { }Copy, #[automatically_derived]
impl ::core::clone::Clone for UniformDurationMode {
    #[inline]
    fn clone(&self) -> UniformDurationMode {
        let _: ::core::clone::AssertParamIsClone<u64>;
        let _: ::core::clone::AssertParamIsClone<Uniform<u32>>;
        let _: ::core::clone::AssertParamIsClone<Uniform<u64>>;
        let _: ::core::clone::AssertParamIsClone<u32>;
        let _: ::core::clone::AssertParamIsClone<Uniform<u64>>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for UniformDurationMode {
    #[inline]
    fn eq(&self, other: &UniformDurationMode) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (UniformDurationMode::Small { secs: __self_0, nanos: __self_1
                    }, UniformDurationMode::Small {
                    secs: __arg1_0, nanos: __arg1_1 }) =>
                    __self_0 == __arg1_0 && __self_1 == __arg1_1,
                (UniformDurationMode::Medium { nanos: __self_0 },
                    UniformDurationMode::Medium { nanos: __arg1_0 }) =>
                    __self_0 == __arg1_0,
                (UniformDurationMode::Large {
                    max_secs: __self_0, max_nanos: __self_1, secs: __self_2 },
                    UniformDurationMode::Large {
                    max_secs: __arg1_0, max_nanos: __arg1_1, secs: __arg1_2 })
                    =>
                    __self_0 == __arg1_0 && __self_1 == __arg1_1 &&
                        __self_2 == __arg1_2,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for UniformDurationMode {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<u64>;
        let _: ::core::cmp::AssertParamIsEq<Uniform<u32>>;
        let _: ::core::cmp::AssertParamIsEq<Uniform<u64>>;
        let _: ::core::cmp::AssertParamIsEq<u32>;
        let _: ::core::cmp::AssertParamIsEq<Uniform<u64>>;
    }
}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                // An offset is applied to simplify generation of nanoseconds
215                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                // constant folding means this is at least as fast as `Rng::sample(Range)`
246                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)] // Miri is too slow
276    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)] // Miri is too slow
336    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}