Coverage Report

Created: 2024-08-22 06:13

/rust/registry/src/index.crates.io-6f17d22bba15001f/fastrand-2.1.0/src/global_rng.rs
Line
Count
Source (jump to first uncovered line)
1
//! A global, thread-local random number generator.
2
3
use crate::Rng;
4
5
use std::cell::Cell;
6
use std::ops::RangeBounds;
7
use std::vec::Vec;
8
9
// Chosen by fair roll of the dice.
10
const DEFAULT_RNG_SEED: u64 = 0xef6f79ed30ba75a;
11
12
impl Default for Rng {
13
    /// Initialize the `Rng` from the system's random number generator.
14
    ///
15
    /// This is equivalent to [`Rng::new()`].
16
    #[inline]
17
0
    fn default() -> Rng {
18
0
        Rng::new()
19
0
    }
20
}
21
22
impl Rng {
23
    /// Creates a new random number generator.
24
    #[inline]
25
0
    pub fn new() -> Rng {
26
0
        try_with_rng(Rng::fork).unwrap_or_else(|_| Rng::with_seed(0x4d595df4d0f33173))
27
0
    }
28
}
29
30
std::thread_local! {
31
    static RNG: Cell<Rng> = Cell::new(Rng(random_seed().unwrap_or(DEFAULT_RNG_SEED)));
32
}
33
34
/// Run an operation with the current thread-local generator.
35
#[inline]
36
0
fn with_rng<R>(f: impl FnOnce(&mut Rng) -> R) -> R {
37
0
    RNG.with(|rng| {
38
0
        let current = rng.replace(Rng(0));
39
0
40
0
        let mut restore = RestoreOnDrop { rng, current };
41
0
42
0
        f(&mut restore.current)
43
0
    })
Unexecuted instantiation: fastrand::global_rng::with_rng::<f64, fastrand::global_rng::f64::{closure#0}>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::with_rng::<f32, fastrand::global_rng::f32::{closure#0}>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::with_rng::<char, fastrand::global_rng::alphanumeric::{closure#0}>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::with_rng::<usize, fastrand::global_rng::usize<core::ops::range::RangeInclusive<usize>>::{closure#0}>::{closure#0}
44
0
}
Unexecuted instantiation: fastrand::global_rng::with_rng::<f64, fastrand::global_rng::f64::{closure#0}>
Unexecuted instantiation: fastrand::global_rng::with_rng::<f32, fastrand::global_rng::f32::{closure#0}>
Unexecuted instantiation: fastrand::global_rng::with_rng::<char, fastrand::global_rng::alphanumeric::{closure#0}>
Unexecuted instantiation: fastrand::global_rng::with_rng::<usize, fastrand::global_rng::usize<core::ops::range::RangeInclusive<usize>>::{closure#0}>
45
46
/// Try to run an operation with the current thread-local generator.
47
#[inline]
48
0
fn try_with_rng<R>(f: impl FnOnce(&mut Rng) -> R) -> Result<R, std::thread::AccessError> {
49
0
    RNG.try_with(|rng| {
50
0
        let current = rng.replace(Rng(0));
51
0
52
0
        let mut restore = RestoreOnDrop { rng, current };
53
0
54
0
        f(&mut restore.current)
55
0
    })
56
0
}
57
58
/// Make sure the original RNG is restored even on panic.
59
struct RestoreOnDrop<'a> {
60
    rng: &'a Cell<Rng>,
61
    current: Rng,
62
}
63
64
impl Drop for RestoreOnDrop<'_> {
65
0
    fn drop(&mut self) {
66
0
        self.rng.set(Rng(self.current.0));
67
0
    }
68
}
69
70
/// Initializes the thread-local generator with the given seed.
71
#[inline]
72
0
pub fn seed(seed: u64) {
73
0
    with_rng(|r| r.seed(seed));
74
0
}
75
76
/// Gives back **current** seed that is being held by the thread-local generator.
77
#[inline]
78
0
pub fn get_seed() -> u64 {
79
0
    with_rng(|r| r.get_seed())
80
0
}
81
82
/// Generates a random `bool`.
83
#[inline]
84
0
pub fn bool() -> bool {
85
0
    with_rng(|r| r.bool())
86
0
}
87
88
/// Generates a random `char` in ranges a-z and A-Z.
89
#[inline]
90
0
pub fn alphabetic() -> char {
91
0
    with_rng(|r| r.alphabetic())
92
0
}
93
94
/// Generates a random `char` in ranges a-z, A-Z and 0-9.
95
#[inline]
96
0
pub fn alphanumeric() -> char {
97
0
    with_rng(|r| r.alphanumeric())
Unexecuted instantiation: fastrand::global_rng::alphanumeric::{closure#0}
Unexecuted instantiation: fastrand::global_rng::alphanumeric::{closure#0}
98
0
}
Unexecuted instantiation: fastrand::global_rng::alphanumeric
Unexecuted instantiation: fastrand::global_rng::alphanumeric
99
100
/// Generates a random `char` in range a-z.
101
#[inline]
102
0
pub fn lowercase() -> char {
103
0
    with_rng(|r| r.lowercase())
104
0
}
105
106
/// Generates a random `char` in range A-Z.
107
#[inline]
108
0
pub fn uppercase() -> char {
109
0
    with_rng(|r| r.uppercase())
110
0
}
111
112
/// Choose an item from an iterator at random.
113
///
114
/// This function may have an unexpected result if the `len()` property of the
115
/// iterator does not match the actual number of items in the iterator. If
116
/// the iterator is empty, this returns `None`.
117
#[inline]
118
0
pub fn choice<I>(iter: I) -> Option<I::Item>
119
0
where
120
0
    I: IntoIterator,
121
0
    I::IntoIter: ExactSizeIterator,
122
0
{
123
0
    with_rng(|r| r.choice(iter))
124
0
}
125
126
/// Generates a random digit in the given `base`.
127
///
128
/// Digits are represented by `char`s in ranges 0-9 and a-z.
129
///
130
/// Panics if the base is zero or greater than 36.
131
#[inline]
132
0
pub fn digit(base: u32) -> char {
133
0
    with_rng(|r| r.digit(base))
134
0
}
135
136
/// Shuffles a slice randomly.
137
#[inline]
138
0
pub fn shuffle<T>(slice: &mut [T]) {
139
0
    with_rng(|r| r.shuffle(slice))
140
0
}
141
142
macro_rules! integer {
143
    ($t:tt, $doc:tt) => {
144
        #[doc = $doc]
145
        ///
146
        /// Panics if the range is empty.
147
        #[inline]
148
0
        pub fn $t(range: impl RangeBounds<$t>) -> $t {
149
0
            with_rng(|r| r.$t(range))
Unexecuted instantiation: fastrand::global_rng::u8::<_>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::i8::<_>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::u16::<_>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::i16::<_>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::u32::<_>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::i32::<_>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::u64::<_>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::i64::<_>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::u128::<_>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::i128::<_>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::usize::<_>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::isize::<_>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::char::<_>::{closure#0}
Unexecuted instantiation: fastrand::global_rng::usize::<core::ops::range::RangeInclusive<usize>>::{closure#0}
150
0
        }
Unexecuted instantiation: fastrand::global_rng::u8::<_>
Unexecuted instantiation: fastrand::global_rng::i8::<_>
Unexecuted instantiation: fastrand::global_rng::u16::<_>
Unexecuted instantiation: fastrand::global_rng::i16::<_>
Unexecuted instantiation: fastrand::global_rng::u32::<_>
Unexecuted instantiation: fastrand::global_rng::i32::<_>
Unexecuted instantiation: fastrand::global_rng::u64::<_>
Unexecuted instantiation: fastrand::global_rng::i64::<_>
Unexecuted instantiation: fastrand::global_rng::u128::<_>
Unexecuted instantiation: fastrand::global_rng::i128::<_>
Unexecuted instantiation: fastrand::global_rng::usize::<_>
Unexecuted instantiation: fastrand::global_rng::isize::<_>
Unexecuted instantiation: fastrand::global_rng::char::<_>
Unexecuted instantiation: fastrand::global_rng::usize::<core::ops::range::RangeInclusive<usize>>
151
    };
152
}
153
154
integer!(u8, "Generates a random `u8` in the given range.");
155
integer!(i8, "Generates a random `i8` in the given range.");
156
integer!(u16, "Generates a random `u16` in the given range.");
157
integer!(i16, "Generates a random `i16` in the given range.");
158
integer!(u32, "Generates a random `u32` in the given range.");
159
integer!(i32, "Generates a random `i32` in the given range.");
160
integer!(u64, "Generates a random `u64` in the given range.");
161
integer!(i64, "Generates a random `i64` in the given range.");
162
integer!(u128, "Generates a random `u128` in the given range.");
163
integer!(i128, "Generates a random `i128` in the given range.");
164
integer!(usize, "Generates a random `usize` in the given range.");
165
integer!(isize, "Generates a random `isize` in the given range.");
166
integer!(char, "Generates a random `char` in the given range.");
167
168
/// Generates a random `f32` in range `0..1`.
169
0
pub fn f32() -> f32 {
170
0
    with_rng(|r| r.f32())
171
0
}
172
173
/// Generates a random `f64` in range `0..1`.
174
0
pub fn f64() -> f64 {
175
0
    with_rng(|r| r.f64())
176
0
}
177
178
/// Collects `amount` values at random from the iterator into a vector.
179
0
pub fn choose_multiple<T: Iterator>(source: T, amount: usize) -> Vec<T::Item> {
180
0
    with_rng(|rng| rng.choose_multiple(source, amount))
181
0
}
182
183
#[cfg(not(all(
184
    any(target_arch = "wasm32", target_arch = "wasm64"),
185
    target_os = "unknown"
186
)))]
187
0
fn random_seed() -> Option<u64> {
188
0
    use std::collections::hash_map::DefaultHasher;
189
0
    use std::hash::{Hash, Hasher};
190
0
    use std::thread;
191
0
    use std::time::Instant;
192
0
193
0
    let mut hasher = DefaultHasher::new();
194
0
    Instant::now().hash(&mut hasher);
195
0
    thread::current().id().hash(&mut hasher);
196
0
    Some(hasher.finish())
197
0
}
198
199
#[cfg(all(
200
    any(target_arch = "wasm32", target_arch = "wasm64"),
201
    target_os = "unknown",
202
    feature = "js"
203
))]
204
fn random_seed() -> Option<u64> {
205
    // TODO(notgull): Failures should be logged somewhere.
206
    let mut seed = [0u8; 8];
207
    getrandom::getrandom(&mut seed).ok()?;
208
    Some(u64::from_ne_bytes(seed))
209
}
210
211
#[cfg(all(
212
    any(target_arch = "wasm32", target_arch = "wasm64"),
213
    target_os = "unknown",
214
    not(feature = "js")
215
))]
216
fn random_seed() -> Option<u64> {
217
    None
218
}