1#![cfg_attr(not(feature = "std"), no_std)]
2
3pub mod rng;
4pub mod rng_alphanumeric;
5pub use rng::AxRng;
6
7#[cfg(feature = "std")]
8use std::cell::Cell;
9
10#[cfg(feature = "std")]
11thread_local! {
12 static THREAD_RNG: Cell<AxRng> = Cell::new(AxRng::new({
13 use std::time::{SystemTime, UNIX_EPOCH};
14 SystemTime::now()
15 .duration_since(UNIX_EPOCH)
16 .unwrap_or_else(|_| std::time::Duration::from_nanos(0xA0761D6478BD642F))
17 .as_nanos() as u64
18 }));
19}
20
21#[cfg(feature = "std")]
23#[inline(always)]
24pub fn u8() -> u8 {
25 THREAD_RNG.with(|rng| {
26 let mut r = rng.get();
27 let v = r.next_u8();
28 rng.set(r);
29 v
30 })
31}
32
33#[cfg(feature = "std")]
34#[inline(always)]
35pub fn u16() -> u16 {
36 THREAD_RNG.with(|rng| {
37 let mut r = rng.get();
38 let v = r.next_u16();
39 rng.set(r);
40 v
41 })
42}
43
44#[cfg(feature = "std")]
45#[inline(always)]
46pub fn u32() -> u32 {
47 THREAD_RNG.with(|rng| {
48 let mut r = rng.get();
49 let v = r.next_u32();
50 rng.set(r);
51 v
52 })
53}
54
55#[cfg(feature = "std")]
56#[inline(always)]
57pub fn u64() -> u64 {
58 THREAD_RNG.with(|rng| {
59 let mut r = rng.get();
60 let v = r.next_u64();
61 rng.set(r);
62 v
63 })
64}
65
66#[cfg(feature = "std")]
67#[inline(always)]
68pub fn bool() -> bool {
69 THREAD_RNG.with(|rng| {
70 let mut r = rng.get();
71 let v = r.next_bool();
72 rng.set(r);
73 v
74 })
75}
76
77#[cfg(feature = "std")]
78#[inline(always)]
79pub fn f32() -> f32 {
80 THREAD_RNG.with(|rng| {
81 let mut r = rng.get();
82 let v = r.next_f32();
83 rng.set(r);
84 v
85 })
86}
87
88#[cfg(feature = "std")]
89#[inline(always)]
90pub fn f64() -> f64 {
91 THREAD_RNG.with(|rng| {
92 let mut r = rng.get();
93 let v = r.next_f64();
94 rng.set(r);
95 v
96 })
97}
98
99#[cfg(feature = "std")]
100#[inline(always)]
101pub fn alphanumeric(len: usize) -> String {
102 THREAD_RNG.with(|rng| {
103 let mut r = rng.get();
104 let v = r.next_alphanumeric(len);
105 rng.set(r);
106 v
107 })
108}
109
110#[cfg(feature = "std")]
111#[inline(always)]
112pub fn base64url(len: usize) -> String {
113 THREAD_RNG.with(|rng| {
114 let mut r = rng.get();
115 let v = r.next_base64url(len);
116 rng.set(r);
117 v
118 })
119}
120
121#[cfg(feature = "std")]
122#[inline(always)]
123pub fn fill(out: &mut [u8]) {
124 THREAD_RNG.with(|rng| {
125 let mut r = rng.get();
126 r.fill_bytes(out);
127 rng.set(r);
128 })
129}
130
131#[cfg(feature = "std")]
132#[inline(always)]
133pub fn with_rng<F, R>(f: F) -> R
134where
135 F: FnOnce(&mut AxRng) -> R,
136{
137 THREAD_RNG.with(|rng| {
138 let mut r = rng.get();
139 let result = f(&mut r);
140 rng.set(r);
141 result
142 })
143}
144
145#[inline]
146pub fn rng(seed: u64) -> AxRng {
147 AxRng::new(seed)
148}
149
150#[inline(always)]
151pub fn fill_bytes(rng: &mut AxRng, out: &mut [u8]) {
152 rng::fill_bytes(rng, out)
153}
154
155#[inline(always)]
156pub fn fill_u64(rng: &mut AxRng, out: &mut [u64]) {
157 rng::fill_u64(rng, out)
158}
159
160#[inline(always)]
161pub fn fill_u32(rng: &mut AxRng, out: &mut [u32]) {
162 rng::fill_u32(rng, out)
163}
164
165#[inline(always)]
166pub fn random_u64(seed: u64) -> u64 {
167 let mut rnd = AxRng::new(seed);
168
169 rnd.next_u64()
170}
171
172#[inline(always)]
173pub fn random_u32(seed: u64) -> u32 {
174 let mut rnd = AxRng::new(seed);
175
176 rnd.next_u32()
177}
178
179#[inline(always)]
180pub fn random_bool(seed: u64) -> bool {
181 let mut rnd = AxRng::new(seed);
182
183 rnd.next_bool()
184}
185
186#[inline(always)]
187pub fn random_f64(seed: u64) -> f64 {
188 let mut rnd = AxRng::new(seed);
189
190 rnd.next_f64()
191}
192
193#[inline(always)]
194pub fn bounded_u64(seed: u64, upper: u64) -> u64 {
195 assert!(upper > 0, "upper must be > 0");
196
197 let mut rnd = AxRng::new(seed);
198
199 rnd.bounded_u64(upper)
200}
201
202#[inline(always)]
203pub fn random_alphanumeric(seed: u64, len: usize) -> String {
204 let mut rnd = AxRng::new(seed);
205 rnd.next_alphanumeric(len)
206}
207
208#[inline(always)]
209pub fn alpha(seed: u64, len: usize) -> String {
210 let mut rnd = AxRng::new(seed);
211 rnd.alpha(len)
212}
213
214#[inline(always)]
215pub fn random_base64url(seed: u64, len: usize) -> String {
216 let mut rnd = AxRng::new(seed);
217 rnd.next_base64url(len)
218}
219
220#[inline(always)]
221pub fn token(seed: u64, len: usize) -> String {
222 let mut rnd = AxRng::new(seed);
223 rnd.token(len)
224}
225
226#[cfg(test)]
227mod tests {
228 use super::*;
229
230 #[test]
231 fn deterministic() {
232 let mut a = rng(123);
233 let mut b = rng(123);
234
235 for _ in 0..1000 {
236 assert_eq!(a.next_u64(), b.next_u64(),);
237 }
238 }
239
240 #[test]
241 fn fill_bytes_works() {
242 let mut rng = rng(999);
243
244 let mut buf = [0u8; 128];
245
246 fill_bytes(&mut rng, &mut buf);
247
248 let mut zero = true;
249
250 for b in buf {
251 if b != 0 {
252 zero = false;
253 break;
254 }
255 }
256
257 assert!(!zero);
258 }
259
260 #[test]
261 fn split_is_different() {
262 let mut a = rng(42);
263
264 let mut b = a.split();
265
266 assert_ne!(a.next_u64(), b.next_u64(),);
267 }
268
269 #[test]
270 fn bounded_range() {
271 let mut rng = rng(123);
272
273 for _ in 0..10000 {
274 let v = rng.bounded_u64(10);
275
276 assert!(v < 10);
277 }
278 }
279
280 #[cfg(feature = "std")]
281 #[test]
282 fn convenience_api_u8() {
283 let v = u8();
284 assert!(v > 0 || true); }
286
287 #[cfg(feature = "std")]
288 #[test]
289 fn convenience_api_u16() {
290 let v = u16();
291 assert!(v > 0 || true);
292 }
293
294 #[cfg(feature = "std")]
295 #[test]
296 fn convenience_api_u32() {
297 let v = u32();
298 assert!(v > 0 || true);
299 }
300
301 #[cfg(feature = "std")]
302 #[test]
303 fn convenience_api_u64() {
304 let v = u64();
305 assert!(v > 0 || true);
306 }
307
308 #[cfg(feature = "std")]
309 #[test]
310 fn convenience_api_bool() {
311 let v = bool();
312 assert!(v == true || v == false);
313 }
314
315 #[cfg(feature = "std")]
316 #[test]
317 fn convenience_api_f32() {
318 let v = f32();
319 assert!(v >= 0.0 && v < 1.0);
320 }
321
322 #[cfg(feature = "std")]
323 #[test]
324 fn convenience_api_f64() {
325 let v = f64();
326 assert!(v >= 0.0 && v < 1.0);
327 }
328
329 #[cfg(feature = "std")]
330 #[test]
331 fn convenience_api_alphanumeric() {
332 let s = alphanumeric(32);
333 assert_eq!(s.len(), 32);
334 assert!(s.chars().all(|c| c.is_ascii_alphanumeric()));
335 }
336
337 #[cfg(feature = "std")]
338 #[test]
339 fn convenience_api_base64url() {
340 let s = base64url(32);
341 assert_eq!(s.len(), 32);
342 assert!(
343 s.chars()
344 .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_')
345 );
346 }
347
348 #[cfg(feature = "std")]
349 #[test]
350 fn convenience_api_fill() {
351 let mut buf = [0u8; 64];
352 fill(&mut buf);
353 let mut all_zero = true;
354 for b in buf {
355 if b != 0 {
356 all_zero = false;
357 break;
358 }
359 }
360 assert!(!all_zero);
361 }
362
363 #[cfg(feature = "std")]
364 #[test]
365 fn convenience_api_with_rng() {
366 let v = with_rng(|rng| rng.next_u64());
367 assert!(v > 0 || true);
368 }
369}