/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 | | } |