1use crate::Rng;
4
5use std::cell::Cell;
6use std::ops::RangeBounds;
7use std::vec::Vec;
8
9const DEFAULT_RNG_SEED: u64 = 0xef6f79ed30ba75a;
11
12impl Default for Rng {
13 #[inline]
17 fn default() -> Rng {
18 Rng::new()
19 }
20}
21
22impl Rng {
23 #[inline]
25 pub fn new() -> Rng {
26 try_with_rng(Rng::fork).unwrap_or_else(|_| Rng::with_seed(0x4d595df4d0f33173))
27 }
28}
29
30std::thread_local! {
31 static RNG: Cell<Rng> = Cell::new(Rng(random_seed().unwrap_or(DEFAULT_RNG_SEED)));
32}
33
34#[inline]
36fn with_rng<R>(f: impl FnOnce(&mut Rng) -> R) -> R {
37 RNG.with(|rng| {
38 let current = rng.replace(Rng(0));
39
40 let mut restore = RestoreOnDrop { rng, current };
41
42 f(&mut restore.current)
43 })
44}
45
46#[inline]
48fn try_with_rng<R>(f: impl FnOnce(&mut Rng) -> R) -> Result<R, std::thread::AccessError> {
49 RNG.try_with(|rng| {
50 let current = rng.replace(Rng(0));
51
52 let mut restore = RestoreOnDrop { rng, current };
53
54 f(&mut restore.current)
55 })
56}
57
58struct RestoreOnDrop<'a> {
60 rng: &'a Cell<Rng>,
61 current: Rng,
62}
63
64impl Drop for RestoreOnDrop<'_> {
65 fn drop(&mut self) {
66 self.rng.set(Rng(self.current.0));
67 }
68}
69
70#[inline]
72pub fn seed(seed: u64) {
73 with_rng(|r| r.seed(seed));
74}
75
76#[inline]
78pub fn get_seed() -> u64 {
79 with_rng(|r| r.get_seed())
80}
81
82#[inline]
84pub fn bool() -> bool {
85 with_rng(|r| r.bool())
86}
87
88#[inline]
90pub fn alphabetic() -> char {
91 with_rng(|r| r.alphabetic())
92}
93
94#[inline]
96pub fn alphanumeric() -> char {
97 with_rng(|r| r.alphanumeric())
98}
99
100#[inline]
102pub fn lowercase() -> char {
103 with_rng(|r| r.lowercase())
104}
105
106#[inline]
108pub fn uppercase() -> char {
109 with_rng(|r| r.uppercase())
110}
111
112#[inline]
118pub fn choice<I>(iter: I) -> Option<I::Item>
119where
120 I: IntoIterator,
121 I::IntoIter: ExactSizeIterator,
122{
123 with_rng(|r| r.choice(iter))
124}
125
126#[inline]
132pub fn digit(base: u32) -> char {
133 with_rng(|r| r.digit(base))
134}
135
136#[inline]
138pub fn shuffle<T>(slice: &mut [T]) {
139 with_rng(|r| r.shuffle(slice))
140}
141
142#[inline]
144pub fn fill(slice: &mut [u8]) {
145 with_rng(|r| r.fill(slice))
146}
147
148macro_rules! integer {
149 ($t:tt, $doc:tt) => {
150 #[doc = $doc]
151 #[inline]
154 pub fn $t(range: impl RangeBounds<$t>) -> $t {
155 with_rng(|r| r.$t(range))
156 }
157 };
158}
159
160integer!(u8, "Generates a random `u8` in the given range.");
161integer!(i8, "Generates a random `i8` in the given range.");
162integer!(u16, "Generates a random `u16` in the given range.");
163integer!(i16, "Generates a random `i16` in the given range.");
164integer!(u32, "Generates a random `u32` in the given range.");
165integer!(i32, "Generates a random `i32` in the given range.");
166integer!(u64, "Generates a random `u64` in the given range.");
167integer!(i64, "Generates a random `i64` in the given range.");
168integer!(u128, "Generates a random `u128` in the given range.");
169integer!(i128, "Generates a random `i128` in the given range.");
170integer!(usize, "Generates a random `usize` in the given range.");
171integer!(isize, "Generates a random `isize` in the given range.");
172integer!(char, "Generates a random `char` in the given range.");
173
174pub fn f32() -> f32 {
176 with_rng(|r| r.f32())
177}
178
179pub fn f64() -> f64 {
181 with_rng(|r| r.f64())
182}
183
184pub fn choose_multiple<I: IntoIterator>(source: I, amount: usize) -> Vec<I::Item> {
186 with_rng(|rng| rng.choose_multiple(source, amount))
187}
188
189#[cfg(not(all(
190 any(target_arch = "wasm32", target_arch = "wasm64"),
191 target_os = "unknown"
192)))]
193fn random_seed() -> Option<u64> {
194 use std::collections::hash_map::DefaultHasher;
195 use std::hash::{Hash, Hasher};
196 use std::thread;
197 use std::time::Instant;
198
199 let mut hasher = DefaultHasher::new();
200 Instant::now().hash(&mut hasher);
201 thread::current().id().hash(&mut hasher);
202 Some(hasher.finish())
203}
204
205#[cfg(all(
206 any(target_arch = "wasm32", target_arch = "wasm64"),
207 target_os = "unknown",
208 feature = "js"
209))]
210fn random_seed() -> Option<u64> {
211 let mut seed = [0u8; 8];
213 getrandom::getrandom(&mut seed).ok()?;
214 Some(u64::from_ne_bytes(seed))
215}
216
217#[cfg(all(
218 any(target_arch = "wasm32", target_arch = "wasm64"),
219 target_os = "unknown",
220 not(feature = "js")
221))]
222fn random_seed() -> Option<u64> {
223 None
224}