// Copyright 2018 Developers of the Rand project. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms.
//! The implementations of the `Standard` distribution for other built-in types.
use core::char; use core::num::Wrapping; #[cfg(feature = "alloc")] use alloc::string::String;
#[cfg(feature = "serde1")] use serde::{Serialize, Deserialize}; #[cfg(feature = "min_const_gen")] use core::mem::{self, MaybeUninit};
// ----- Sampling distributions -----
/// Sample a `u8`, uniformly distributed over ASCII letters and numbers: /// a-z, A-Z and 0-9. /// /// # Example /// /// ``` /// use rand::{Rng, thread_rng}; /// use rand::distributions::Alphanumeric; /// /// let mut rng = thread_rng(); /// let chars: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect(); /// println!("Random chars: {}", chars); /// ``` /// /// The [`DistString`] trait provides an easier method of generating /// a random `String`, and offers more efficient allocation: /// ``` /// use rand::distributions::{Alphanumeric, DistString}; /// let string = Alphanumeric.sample_string(&mut rand::thread_rng(), 16); /// println!("Random string: {}", string); /// ``` /// /// # Passwords /// /// Users sometimes ask whether it is safe to use a string of random characters /// as a password. In principle, all RNGs in Rand implementing `CryptoRng` are /// suitable as a source of randomness for generating passwords (if they are /// properly seeded), but it is more conservative to only use randomness /// directly from the operating system via the `getrandom` crate, or the /// corresponding bindings of a crypto library. /// /// When generating passwords or keys, it is important to consider the threat /// model and in some cases the memorability of the password. This is out of /// scope of the Rand project, and therefore we defer to the following /// references: /// /// - [Wikipedia article on Password Strength](https://en.wikipedia.org/wiki/Password_strength) /// - [Diceware for generating memorable passwords](https://en.wikipedia.org/wiki/Diceware) #[derive(Debug, Clone, Copy)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] pubstruct Alphanumeric;
// ----- Implementations of distributions -----
impl Distribution<char> for Standard { #[inline] fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char { // A valid `char` is either in the interval `[0, 0xD800)` or // `(0xDFFF, 0x11_0000)`. All `char`s must therefore be in // `[0, 0x11_0000)` but not in the "gap" `[0xD800, 0xDFFF]` which is // reserved for surrogates. This is the size of that gap. const GAP_SIZE: u32 = 0xDFFF - 0xD800 + 1;
// Uniform::new(0, 0x11_0000 - GAP_SIZE) can also be used but it // seemed slower. let range = Uniform::new(GAP_SIZE, 0x11_0000);
letmut n = range.sample(rng); if n <= 0xDFFF {
n -= GAP_SIZE;
} unsafe { char::from_u32_unchecked(n) }
}
}
/// Note: the `String` is potentially left with excess capacity; optionally the /// user may call `string.shrink_to_fit()` afterwards. #[cfg(feature = "alloc")] impl DistString for Standard { fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, s: &mut String, len: usize) { // A char is encoded with at most four bytes, thus this reservation is // guaranteed to be sufficient. We do not shrink_to_fit afterwards so // that repeated usage on the same `String` buffer does not reallocate.
s.reserve(4 * len);
s.extend(Distribution::<char>::sample_iter(self, rng).take(len));
}
}
impl Distribution<u8> for Alphanumeric { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 { const RANGE: u32 = 26 + 26 + 10; const GEN_ASCII_STR_CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\ 0123456789"; // We can pick from 62 characters. This is so close to a power of 2, 64, // that we can do better than `Uniform`. Use a simple bitshift and // rejection sampling. We do not use a bitmask, because for small RNGs // the most significant bits are usually of higher quality. loop { let var = rng.next_u32() >> (32 - 6); if var < RANGE { return GEN_ASCII_STR_CHARSET[var as usize];
}
}
}
}
impl Distribution<bool> for Standard { #[inline] fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool { // We can compare against an arbitrary bit of an u32 to get a bool. // Because the least significant bits of a lower quality RNG can have // simple patterns, we compare against the most significant bit. This is // easiest done using a sign test.
(rng.next_u32() as i32) < 0
}
}
macro_rules! tuple_impl { // use variables to indicate the arity of the tuple
($($tyvar:ident),* ) => { // the trailing commas are for the 1 tuple impl< $( $tyvar ),* >
Distribution<( $( $tyvar ),* , )> for Standard where $( Standard: Distribution<$tyvar> ),*
{ #[inline] fn sample<R: Rng + ?Sized>(&self, _rng: &mutR) -> ( $( $tyvar ),* , ) {
( // use the $tyvar's to get the appropriate number of // repeats (they're not actually needed)
$(
_rng.gen::<$tyvar>()
),*
,
)
}
}
}
}
impl Distribution<()> for Standard { #[allow(clippy::unused_unit)] #[inline] fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () {
()
}
}
tuple_impl! {A}
tuple_impl! {A, B}
tuple_impl! {A, B, C}
tuple_impl! {A, B, C, D}
tuple_impl! {A, B, C, D, E}
tuple_impl! {A, B, C, D, E, F}
tuple_impl! {A, B, C, D, E, F, G}
tuple_impl! {A, B, C, D, E, F, G, H}
tuple_impl! {A, B, C, D, E, F, G, H, I}
tuple_impl! {A, B, C, D, E, F, G, H, I, J}
tuple_impl! {A, B, C, D, E, F, G, H, I, J, K}
tuple_impl! {A, B, C, D, E, F, G, H, I, J, K, L}
for elem in &mut buff {
*elem = MaybeUninit::new(_rng.gen());
}
unsafe { mem::transmute_copy::<_, _>(&buff) }
}
}
#[cfg(not(feature = "min_const_gen"))]
macro_rules! array_impl { // recursive, given at least one type parameter:
{$n:expr, $t:ident, $($ts:ident,)*} => {
array_impl!{($n - 1), $($ts,)*}
// Test by generating a relatively large number of chars, so we also // take the rejection sampling path. let word: String = iter::repeat(())
.map(|()| rng.gen::<char>())
.take(1000)
.collect();
assert!(!word.is_empty());
}
// Test by generating a relatively large number of chars, so we also // take the rejection sampling path. letmut incorrect = false; for _ in0..100 { let c: char = rng.sample(Alphanumeric).into();
incorrect |= !(('0'..='9').contains(&c) ||
('A'..='Z').contains(&c) ||
('a'..='z').contains(&c) );
}
assert!(!incorrect);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.