Skip to main content

rand/distr/
other.rs

1// Copyright 2018 Developers of the Rand project.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! The implementations of the `StandardUniform` distribution for other built-in types.
10
11#[cfg(feature = "alloc")]
12use alloc::string::String;
13use core::array;
14use core::char;
15use core::num::Wrapping;
16
17#[cfg(feature = "alloc")]
18use crate::distr::SampleString;
19use crate::distr::{Distribution, StandardUniform, Uniform};
20use crate::{Rng, RngExt};
21
22#[cfg(feature = "simd_support")]
23use core::simd::MaskElement;
24#[cfg(feature = "simd_support")]
25use core::simd::prelude::*;
26#[cfg(feature = "serde")]
27use serde::{Deserialize, Serialize};
28
29// ----- Sampling distributions -----
30
31/// Sample a `u8`, uniformly distributed over ASCII letters and numbers:
32/// a-z, A-Z and 0-9.
33///
34/// # Example
35///
36/// ```
37/// use rand::RngExt;
38/// use rand::distr::Alphanumeric;
39///
40/// let mut rng = rand::rng();
41/// let chars: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect();
42/// println!("Random chars: {}", chars);
43/// ```
44///
45/// The [`SampleString`] trait provides an easier method of generating
46/// a random [`String`], and offers more efficient allocation:
47/// ```
48/// use rand::distr::{Alphanumeric, SampleString};
49/// let string = Alphanumeric.sample_string(&mut rand::rng(), 16);
50/// println!("Random string: {}", string);
51/// ```
52///
53/// # Passwords
54///
55/// Users sometimes ask whether it is safe to use a string of random characters
56/// as a password. In principle, all RNGs in Rand implementing `CryptoRng` are
57/// suitable as a source of randomness for generating passwords (if they are
58/// properly seeded), but it is more conservative to only use randomness
59/// directly from the operating system via the `getrandom` crate, or the
60/// corresponding bindings of a crypto library.
61///
62/// When generating passwords or keys, it is important to consider the threat
63/// model and in some cases the memorability of the password. This is out of
64/// scope of the Rand project, and therefore we defer to the following
65/// references:
66///
67/// - [Wikipedia article on Password Strength](https://en.wikipedia.org/wiki/Password_strength)
68/// - [Diceware for generating memorable passwords](https://en.wikipedia.org/wiki/Diceware)
69#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Alphanumeric {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "Alphanumeric")
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for Alphanumeric {
    #[inline]
    fn clone(&self) -> Alphanumeric { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Alphanumeric { }Copy, #[automatically_derived]
impl ::core::default::Default for Alphanumeric {
    #[inline]
    fn default() -> Alphanumeric { Alphanumeric {} }
}Default)]
70#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
71pub struct Alphanumeric;
72
73/// Sample a [`u8`], uniformly distributed over letters:
74/// a-z and A-Z.
75///
76/// # Example
77///
78/// You're able to generate random Alphabetic characters via mapping or via the
79/// [`SampleString::sample_string`] method like so:
80///
81/// ```
82/// use rand::RngExt;
83/// use rand::distr::{Alphabetic, SampleString};
84///
85/// // Manual mapping
86/// let mut rng = rand::rng();
87/// let chars: String = (0..7).map(|_| rng.sample(Alphabetic) as char).collect();
88/// println!("Random chars: {}", chars);
89///
90/// // Using [`SampleString::sample_string`]
91/// let string = Alphabetic.sample_string(&mut rand::rng(), 16);
92/// println!("Random string: {}", string);
93/// ```
94///
95/// # Passwords
96///
97/// Refer to [`Alphanumeric#Passwords`].
98#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Alphabetic {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "Alphabetic")
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for Alphabetic {
    #[inline]
    fn clone(&self) -> Alphabetic { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Alphabetic { }Copy, #[automatically_derived]
impl ::core::default::Default for Alphabetic {
    #[inline]
    fn default() -> Alphabetic { Alphabetic {} }
}Default)]
99#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
100pub struct Alphabetic;
101
102// ----- Implementations of distributions -----
103
104impl Distribution<char> for StandardUniform {
105    #[inline]
106    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
107        // A valid `char` is either in the interval `[0, 0xD800)` or
108        // `(0xDFFF, 0x11_0000)`. All `char`s must therefore be in
109        // `[0, 0x11_0000)` but not in the "gap" `[0xD800, 0xDFFF]` which is
110        // reserved for surrogates. This is the size of that gap.
111        const GAP_SIZE: u32 = 0xDFFF - 0xD800 + 1;
112
113        // Uniform::new(0, 0x11_0000 - GAP_SIZE) can also be used, but it
114        // seemed slower.
115        let range = Uniform::new(GAP_SIZE, 0x11_0000).unwrap();
116
117        let mut n = range.sample(rng);
118        if n <= 0xDFFF {
119            n -= GAP_SIZE;
120        }
121        // SAFETY: We ensure above that `n` represents a `char`.
122        unsafe { char::from_u32_unchecked(n) }
123    }
124}
125
126#[cfg(feature = "alloc")]
127impl SampleString for StandardUniform {
128    fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, s: &mut String, len: usize) {
129        // A char is encoded with at most four bytes, thus this reservation is
130        // guaranteed to be sufficient. We do not shrink_to_fit afterwards so
131        // that repeated usage on the same `String` buffer does not reallocate.
132        s.reserve(4 * len);
133        s.extend(Distribution::<char>::sample_iter(self, rng).take(len));
134    }
135}
136
137impl Distribution<u8> for Alphanumeric {
138    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
139        const RANGE: u32 = 26 + 26 + 10;
140        const GEN_ASCII_STR_CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
141                abcdefghijklmnopqrstuvwxyz\
142                0123456789";
143        // We can pick from 62 characters. This is so close to a power of 2, 64,
144        // that we can do better than `Uniform`. Use a simple bitshift and
145        // rejection sampling. We do not use a bitmask, because for small RNGs
146        // the most significant bits are usually of higher quality.
147        loop {
148            let var = rng.next_u32() >> (32 - 6);
149            if var < RANGE {
150                return GEN_ASCII_STR_CHARSET[var as usize];
151            }
152        }
153    }
154}
155
156impl Distribution<u8> for Alphabetic {
157    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
158        const RANGE: u8 = 26 + 26;
159
160        let offset = rng.random_range(0..RANGE) + b'A';
161
162        // Account for upper-cases
163        offset + (offset > b'Z') as u8 * (b'a' - b'Z' - 1)
164    }
165}
166
167#[cfg(feature = "alloc")]
168impl SampleString for Alphanumeric {
169    fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, string: &mut String, len: usize) {
170        // SAFETY: `self` only samples alphanumeric characters, which are valid UTF-8.
171        unsafe {
172            let v = string.as_mut_vec();
173            v.extend(
174                self.sample_iter(rng)
175                    .take(len)
176                    .inspect(|b| debug_assert!(b.is_ascii_alphanumeric())),
177            );
178        }
179    }
180}
181
182#[cfg(feature = "alloc")]
183impl SampleString for Alphabetic {
184    fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, string: &mut String, len: usize) {
185        // SAFETY: With this distribution we guarantee that we're working with valid ASCII
186        // characters.
187        // See [#1590](https://github.com/rust-random/rand/issues/1590).
188        unsafe {
189            let v = string.as_mut_vec();
190            v.reserve_exact(len);
191            v.extend(self.sample_iter(rng).take(len));
192        }
193    }
194}
195
196impl Distribution<bool> for StandardUniform {
197    #[inline]
198    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {
199        // We can compare against an arbitrary bit of an u32 to get a bool.
200        // Because the least significant bits of a lower quality RNG can have
201        // simple patterns, we compare against the most significant bit. This is
202        // easiest done using a sign test.
203        (rng.next_u32() as i32) < 0
204    }
205}
206
207/// Note that on some hardware like x86/64 mask operations like [`_mm_blendv_epi8`]
208/// only care about a single bit. This means that you could use uniform random bits
209/// directly:
210///
211/// ```ignore
212/// // this may be faster...
213/// let x = unsafe { _mm_blendv_epi8(a.into(), b.into(), rng.random::<__m128i>()) };
214///
215/// // ...than this
216/// let x = rng.random::<mask8x16>().select(b, a);
217/// ```
218///
219/// Since most bits are unused you could also generate only as many bits as you need, i.e.:
220/// ```
221/// #![feature(portable_simd)]
222/// use std::simd::prelude::*;
223/// use rand::prelude::*;
224/// let mut rng = rand::rng();
225///
226/// let x = u16x8::splat(rng.random::<u8>() as u16);
227/// let mask = u16x8::splat(1) << u16x8::from([0, 1, 2, 3, 4, 5, 6, 7]);
228/// let rand_mask = (x & mask).simd_eq(mask);
229/// ```
230///
231/// [`_mm_blendv_epi8`]: https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_blendv_epi8&ig_expand=514/
232/// [`simd_support`]: https://github.com/rust-random/rand#crate-features
233#[cfg(feature = "simd_support")]
234impl<T, const LANES: usize> Distribution<Mask<T, LANES>> for StandardUniform
235where
236    T: MaskElement + Default,
237    StandardUniform: Distribution<Simd<T, LANES>>,
238    Simd<T, LANES>: SimdPartialOrd<Mask = Mask<T, LANES>>,
239{
240    #[inline]
241    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Mask<T, LANES> {
242        // `MaskElement` must be a signed integer, so this is equivalent
243        // to the scalar `i32 < 0` method
244        let var = rng.random::<Simd<T, LANES>>();
245        var.simd_lt(Simd::default())
246    }
247}
248
249/// Implement `Distribution<(A, B, C, ...)> for StandardUniform`, using the list of
250/// identifiers
251macro_rules! tuple_impl {
252    ($($tyvar:ident)*) => {
253        impl< $($tyvar,)* > Distribution<($($tyvar,)*)> for StandardUniform
254        where $(
255            StandardUniform: Distribution< $tyvar >,
256        )*
257        {
258            #[inline]
259            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> ( $($tyvar,)* ) {
260                let out = ($(
261                    // use the $tyvar's to get the appropriate number of
262                    // repeats (they're not actually needed)
263                    rng.random::<$tyvar>()
264                ,)*);
265
266                // Suppress the unused variable warning for empty tuple
267                let _rng = rng;
268
269                out
270            }
271        }
272    }
273}
274
275/// Looping wrapper for `tuple_impl`. Given (A, B, C), it also generates
276/// implementations for (A, B) and (A,)
277macro_rules! tuple_impls {
278    ($($tyvar:ident)*) => {tuple_impls!{[] $($tyvar)*}};
279
280    ([$($prefix:ident)*] $head:ident $($tail:ident)*) => {
281        tuple_impl!{$($prefix)*}
282        tuple_impls!{[$($prefix)* $head] $($tail)*}
283    };
284
285
286    ([$($prefix:ident)*]) => {
287        tuple_impl!{$($prefix)*}
288    };
289
290}
291
292impl<A, B, C, D, E, F, G, H, I, J, K, L>
    Distribution<(A, B, C, D, E, F, G, H, I, J, K, L)> for StandardUniform
    where StandardUniform: Distribution<A>, StandardUniform: Distribution<B>,
    StandardUniform: Distribution<C>, StandardUniform: Distribution<D>,
    StandardUniform: Distribution<E>, StandardUniform: Distribution<F>,
    StandardUniform: Distribution<G>, StandardUniform: Distribution<H>,
    StandardUniform: Distribution<I>, StandardUniform: Distribution<J>,
    StandardUniform: Distribution<K>, StandardUniform: Distribution<L> {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R)
        -> (A, B, C, D, E, F, G, H, I, J, K, L) {
        let out =
            (rng.random::<A>(), rng.random::<B>(), rng.random::<C>(),
                rng.random::<D>(), rng.random::<E>(), rng.random::<F>(),
                rng.random::<G>(), rng.random::<H>(), rng.random::<I>(),
                rng.random::<J>(), rng.random::<K>(), rng.random::<L>());
        let _rng = rng;
        out
    }
}tuple_impls! {A B C D E F G H I J K L}
293
294impl<T, const N: usize> Distribution<[T; N]> for StandardUniform
295where
296    StandardUniform: Distribution<T>,
297{
298    #[inline]
299    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [T; N] {
300        array::from_fn(|_| rng.random())
301    }
302}
303
304impl<T> Distribution<Wrapping<T>> for StandardUniform
305where
306    StandardUniform: Distribution<T>,
307{
308    #[inline]
309    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Wrapping<T> {
310        Wrapping(rng.random())
311    }
312}
313
314#[cfg(test)]
315mod tests {
316    use super::*;
317    use crate::Rng;
318
319    #[test]
320    fn test_misc() {
321        let rng: &mut dyn Rng = &mut crate::test::rng(820);
322
323        rng.sample::<char, _>(StandardUniform);
324        rng.sample::<bool, _>(StandardUniform);
325    }
326
327    #[cfg(feature = "alloc")]
328    #[test]
329    fn test_chars() {
330        use core::iter;
331        let mut rng = crate::test::rng(805);
332
333        // Test by generating a relatively large number of chars, so we also
334        // take the rejection sampling path.
335        let word: String = iter::repeat(())
336            .map(|()| rng.random::<char>())
337            .take(1000)
338            .collect();
339        assert!(!word.is_empty());
340    }
341
342    #[test]
343    fn test_alphanumeric() {
344        let mut rng = crate::test::rng(806);
345
346        // Test by generating a relatively large number of chars, so we also
347        // take the rejection sampling path.
348        let mut incorrect = false;
349        for _ in 0..100 {
350            let c: char = rng.sample(Alphanumeric).into();
351            incorrect |= !c.is_ascii_alphanumeric();
352        }
353        assert!(!incorrect);
354    }
355
356    #[test]
357    fn test_alphabetic() {
358        let mut rng = crate::test::rng(806);
359
360        // Test by generating a relatively large number of chars, so we also
361        // take the rejection sampling path.
362        let mut incorrect = false;
363        for _ in 0..100 {
364            let c: char = rng.sample(Alphabetic).into();
365            incorrect |= !c.is_ascii_alphabetic();
366        }
367        assert!(!incorrect);
368    }
369
370    #[test]
371    fn value_stability() {
372        fn test_samples<T: Copy + core::fmt::Debug + PartialEq, D: Distribution<T>>(
373            distr: &D,
374            zero: T,
375            expected: &[T],
376        ) {
377            let mut rng = crate::test::rng(807);
378            let mut buf = [zero; 5];
379            for x in &mut buf {
380                *x = rng.sample(distr);
381            }
382            assert_eq!(&buf, expected);
383        }
384
385        test_samples(
386            &StandardUniform,
387            'a',
388            &[
389                '\u{8cdac}',
390                '\u{a346a}',
391                '\u{80120}',
392                '\u{ed692}',
393                '\u{35888}',
394            ],
395        );
396        test_samples(&Alphanumeric, 0, &[104, 109, 101, 51, 77]);
397        test_samples(&Alphabetic, 0, &[97, 102, 89, 116, 75]);
398        test_samples(&StandardUniform, false, &[true, true, false, true, false]);
399        test_samples(
400            &StandardUniform,
401            Wrapping(0i32),
402            &[
403                Wrapping(-2074640887),
404                Wrapping(-1719949321),
405                Wrapping(2018088303),
406                Wrapping(-547181756),
407                Wrapping(838957336),
408            ],
409        );
410
411        // We test only sub-sets of tuple and array impls
412        test_samples(&StandardUniform, (), &[(), (), (), (), ()]);
413        test_samples(
414            &StandardUniform,
415            (false,),
416            &[(true,), (true,), (false,), (true,), (false,)],
417        );
418        test_samples(
419            &StandardUniform,
420            (false, false),
421            &[
422                (true, true),
423                (false, true),
424                (false, false),
425                (true, false),
426                (false, false),
427            ],
428        );
429
430        test_samples(&StandardUniform, [0u8; 0], &[[], [], [], [], []]);
431        test_samples(
432            &StandardUniform,
433            [0u8; 3],
434            &[
435                [9, 247, 111],
436                [68, 24, 13],
437                [174, 19, 194],
438                [172, 69, 213],
439                [149, 207, 29],
440            ],
441        );
442    }
443}