/ src / lib.rs
lib.rs
  1  //! A simple and fast random number generator.
  2  //!
  3  //! The implementation uses [Wyrand](https://github.com/wangyi-fudan/wyhash), a simple and fast
  4  //! generator but **not** cryptographically secure.
  5  //!
  6  //! # Examples
  7  //!
  8  //! Flip a coin:
  9  //!
 10  //! ```
 11  //! if fastrand::bool() {
 12  //!     println!("heads");
 13  //! } else {
 14  //!     println!("tails");
 15  //! }
 16  //! ```
 17  //!
 18  //! Generate a random `i32`:
 19  //!
 20  //! ```
 21  //! let num = fastrand::i32(..);
 22  //! ```
 23  //!
 24  //! Choose a random element in an array:
 25  //!
 26  //! ```
 27  //! let v = vec![1, 2, 3, 4, 5];
 28  //! let i = fastrand::usize(..v.len());
 29  //! let elem = v[i];
 30  //! ```
 31  //!
 32  //! Shuffle an array:
 33  //!
 34  //! ```
 35  //! let mut v = vec![1, 2, 3, 4, 5];
 36  //! fastrand::shuffle(&mut v);
 37  //! ```
 38  //!
 39  //! Generate a random [`Vec`] or [`String`]:
 40  //!
 41  //! ```
 42  //! use std::iter::repeat_with;
 43  //!
 44  //! let v: Vec<i32> = repeat_with(|| fastrand::i32(..)).take(10).collect();
 45  //! let s: String = repeat_with(fastrand::alphanumeric).take(10).collect();
 46  //! ```
 47  //!
 48  //! To get reproducible results on every run, initialize the generator with a seed:
 49  //!
 50  //! ```
 51  //! // Pick an arbitrary number as seed.
 52  //! fastrand::seed(7);
 53  //!
 54  //! // Now this prints the same number on every run:
 55  //! println!("{}", fastrand::u32(..));
 56  //! ```
 57  //!
 58  //! To be more efficient, create a new [`Rng`] instance instead of using the thread-local
 59  //! generator:
 60  //!
 61  //! ```
 62  //! use std::iter::repeat_with;
 63  //!
 64  //! let rng = fastrand::Rng::new();
 65  //! let mut bytes: Vec<u8> = repeat_with(|| rng.u8(..)).take(10_000).collect();
 66  //! ```
 67  
 68  #![forbid(unsafe_code)]
 69  #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
 70  
 71  use std::cell::Cell;
 72  use std::collections::hash_map::DefaultHasher;
 73  use std::convert::TryInto;
 74  use std::hash::{Hash, Hasher};
 75  use std::ops::{Bound, RangeBounds};
 76  use std::thread;
 77  
 78  #[cfg(target_arch = "wasm32")]
 79  use instant::Instant;
 80  #[cfg(not(target_arch = "wasm32"))]
 81  use std::time::Instant;
 82  
 83  /// A random number generator.
 84  #[derive(Debug, PartialEq, Eq)]
 85  pub struct Rng(Cell<u64>);
 86  
 87  impl Default for Rng {
 88      #[inline]
 89      fn default() -> Rng {
 90          Rng::new()
 91      }
 92  }
 93  
 94  impl Clone for Rng {
 95      /// Clones the generator by deterministically deriving a new generator based on the initial
 96      /// seed.
 97      ///
 98      /// # Example
 99      ///
100      /// ```
101      /// // Seed two generators equally, and clone both of them.
102      /// let base1 = fastrand::Rng::new();
103      /// base1.seed(0x4d595df4d0f33173);
104      /// base1.bool(); // Use the generator once.
105      ///
106      /// let base2 = fastrand::Rng::new();
107      /// base2.seed(0x4d595df4d0f33173);
108      /// base2.bool(); // Use the generator once.
109      ///
110      /// let rng1 = base1.clone();
111      /// let rng2 = base2.clone();
112      ///
113      /// assert_eq!(rng1.u64(..), rng2.u64(..), "the cloned generators are identical");
114      /// ```
115      fn clone(&self) -> Rng {
116          Rng::with_seed(self.gen_u64())
117      }
118  }
119  
120  impl Rng {
121      /// Generates a random `u32`.
122      #[inline]
123      fn gen_u32(&self) -> u32 {
124          self.gen_u64() as u32
125      }
126  
127      /// Generates a random `u64`.
128      #[inline]
129      fn gen_u64(&self) -> u64 {
130          let s = self.0.get().wrapping_add(0xA0761D6478BD642F);
131          self.0.set(s);
132          let t = u128::from(s) * u128::from(s ^ 0xE7037ED1A0B428DB);
133          (t as u64) ^ (t >> 64) as u64
134      }
135  
136      /// Generates a random `u128`.
137      #[inline]
138      fn gen_u128(&self) -> u128 {
139          (u128::from(self.gen_u64()) << 64) | u128::from(self.gen_u64())
140      }
141  
142      /// Generates a random `u32` in `0..n`.
143      #[inline]
144      fn gen_mod_u32(&self, n: u32) -> u32 {
145          // Adapted from: https://lemire.me/blog/2016/06/30/fast-random-shuffling/
146          let mut r = self.gen_u32();
147          let mut hi = mul_high_u32(r, n);
148          let mut lo = r.wrapping_mul(n);
149          if lo < n {
150              let t = n.wrapping_neg() % n;
151              while lo < t {
152                  r = self.gen_u32();
153                  hi = mul_high_u32(r, n);
154                  lo = r.wrapping_mul(n);
155              }
156          }
157          hi
158      }
159  
160      /// Generates a random `u64` in `0..n`.
161      #[inline]
162      fn gen_mod_u64(&self, n: u64) -> u64 {
163          // Adapted from: https://lemire.me/blog/2016/06/30/fast-random-shuffling/
164          let mut r = self.gen_u64();
165          let mut hi = mul_high_u64(r, n);
166          let mut lo = r.wrapping_mul(n);
167          if lo < n {
168              let t = n.wrapping_neg() % n;
169              while lo < t {
170                  r = self.gen_u64();
171                  hi = mul_high_u64(r, n);
172                  lo = r.wrapping_mul(n);
173              }
174          }
175          hi
176      }
177  
178      /// Generates a random `u128` in `0..n`.
179      #[inline]
180      fn gen_mod_u128(&self, n: u128) -> u128 {
181          // Adapted from: https://lemire.me/blog/2016/06/30/fast-random-shuffling/
182          let mut r = self.gen_u128();
183          let mut hi = mul_high_u128(r, n);
184          let mut lo = r.wrapping_mul(n);
185          if lo < n {
186              let t = n.wrapping_neg() % n;
187              while lo < t {
188                  r = self.gen_u128();
189                  hi = mul_high_u128(r, n);
190                  lo = r.wrapping_mul(n);
191              }
192          }
193          hi
194      }
195  }
196  
197  thread_local! {
198      static RNG: Rng = Rng(Cell::new({
199          let mut hasher = DefaultHasher::new();
200          Instant::now().hash(&mut hasher);
201          thread::current().id().hash(&mut hasher);
202          let hash = hasher.finish();
203          (hash << 1) | 1
204      }));
205  }
206  
207  /// Computes `(a * b) >> 32`.
208  #[inline]
209  fn mul_high_u32(a: u32, b: u32) -> u32 {
210      (((a as u64) * (b as u64)) >> 32) as u32
211  }
212  
213  /// Computes `(a * b) >> 64`.
214  #[inline]
215  fn mul_high_u64(a: u64, b: u64) -> u64 {
216      (((a as u128) * (b as u128)) >> 64) as u64
217  }
218  
219  /// Computes `(a * b) >> 128`.
220  #[inline]
221  fn mul_high_u128(a: u128, b: u128) -> u128 {
222      // Adapted from: https://stackoverflow.com/a/28904636
223      let a_lo = a as u64 as u128;
224      let a_hi = (a >> 64) as u64 as u128;
225      let b_lo = b as u64 as u128;
226      let b_hi = (b >> 64) as u64 as u128;
227      let carry = (a_lo * b_lo) >> 64;
228      let carry = ((a_hi * b_lo) as u64 as u128 + (a_lo * b_hi) as u64 as u128 + carry) >> 64;
229      a_hi * b_hi + ((a_hi * b_lo) >> 64) + ((a_lo * b_hi) >> 64) + carry
230  }
231  
232  macro_rules! rng_integer {
233      ($t:tt, $unsigned_t:tt, $gen:tt, $mod:tt, $doc:tt) => {
234          #[doc = $doc]
235          ///
236          /// Panics if the range is empty.
237          #[inline]
238          pub fn $t(&self, range: impl RangeBounds<$t>) -> $t {
239              let panic_empty_range = || {
240                  panic!(
241                      "empty range: {:?}..{:?}",
242                      range.start_bound(),
243                      range.end_bound()
244                  )
245              };
246  
247              let low = match range.start_bound() {
248                  Bound::Unbounded => std::$t::MIN,
249                  Bound::Included(&x) => x,
250                  Bound::Excluded(&x) => x.checked_add(1).unwrap_or_else(panic_empty_range),
251              };
252  
253              let high = match range.end_bound() {
254                  Bound::Unbounded => std::$t::MAX,
255                  Bound::Included(&x) => x,
256                  Bound::Excluded(&x) => x.checked_sub(1).unwrap_or_else(panic_empty_range),
257              };
258  
259              if low > high {
260                  panic_empty_range();
261              }
262  
263              if low == std::$t::MIN && high == std::$t::MAX {
264                  self.$gen() as $t
265              } else {
266                  let len = high.wrapping_sub(low).wrapping_add(1);
267                  low.wrapping_add(self.$mod(len as $unsigned_t as _) as $t)
268              }
269          }
270      };
271  }
272  
273  impl Rng {
274      /// Creates a new random number generator.
275      #[inline]
276      pub fn new() -> Rng {
277          Rng::with_seed(
278              RNG.try_with(|rng| rng.u64(..))
279                  .unwrap_or(0x4d595df4d0f33173),
280          )
281      }
282  
283      /// Creates a new random number generator with the initial seed.
284      #[inline]
285      pub fn with_seed(seed: u64) -> Self {
286          let rng = Rng(Cell::new(0));
287  
288          rng.seed(seed);
289          rng
290      }
291  
292      /// Generates a random `char` in ranges a-z and A-Z.
293      #[inline]
294      pub fn alphabetic(&self) -> char {
295          const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
296          let len = CHARS.len() as u8;
297          let i = self.u8(..len);
298          CHARS[i as usize] as char
299      }
300  
301      /// Generates a random `char` in ranges a-z, A-Z and 0-9.
302      #[inline]
303      pub fn alphanumeric(&self) -> char {
304          const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
305          let len = CHARS.len() as u8;
306          let i = self.u8(..len);
307          CHARS[i as usize] as char
308      }
309  
310      /// Generates a random `bool`.
311      #[inline]
312      pub fn bool(&self) -> bool {
313          self.u8(..) % 2 == 0
314      }
315  
316      /// Generates a random digit in the given `base`.
317      ///
318      /// Digits are represented by `char`s in ranges 0-9 and a-z.
319      ///
320      /// Panics if the base is zero or greater than 36.
321      #[inline]
322      pub fn digit(&self, base: u32) -> char {
323          if base == 0 {
324              panic!("base cannot be zero");
325          }
326          if base > 36 {
327              panic!("base cannot be larger than 36");
328          }
329          let num = self.u8(..base as u8);
330          if num < 10 {
331              (b'0' + num) as char
332          } else {
333              (b'a' + num - 10) as char
334          }
335      }
336  
337      /// Generates a random `f32` in range `0..1`.
338      pub fn f32(&self) -> f32 {
339          let b = 32;
340          let f = std::f32::MANTISSA_DIGITS - 1;
341          f32::from_bits((1 << (b - 2)) - (1 << f) + (self.u32(..) >> (b - f))) - 1.0
342      }
343  
344      /// Generates a random `f64` in range `0..1`.
345      pub fn f64(&self) -> f64 {
346          let b = 64;
347          let f = std::f64::MANTISSA_DIGITS - 1;
348          f64::from_bits((1 << (b - 2)) - (1 << f) + (self.u64(..) >> (b - f))) - 1.0
349      }
350  
351      rng_integer!(
352          i8,
353          u8,
354          gen_u32,
355          gen_mod_u32,
356          "Generates a random `i8` in the given range."
357      );
358  
359      rng_integer!(
360          i16,
361          u16,
362          gen_u32,
363          gen_mod_u32,
364          "Generates a random `i16` in the given range."
365      );
366  
367      rng_integer!(
368          i32,
369          u32,
370          gen_u32,
371          gen_mod_u32,
372          "Generates a random `i32` in the given range."
373      );
374  
375      rng_integer!(
376          i64,
377          u64,
378          gen_u64,
379          gen_mod_u64,
380          "Generates a random `i64` in the given range."
381      );
382  
383      rng_integer!(
384          i128,
385          u128,
386          gen_u128,
387          gen_mod_u128,
388          "Generates a random `i128` in the given range."
389      );
390  
391      #[cfg(target_pointer_width = "16")]
392      rng_integer!(
393          isize,
394          usize,
395          gen_u32,
396          gen_mod_u32,
397          "Generates a random `isize` in the given range."
398      );
399      #[cfg(target_pointer_width = "32")]
400      rng_integer!(
401          isize,
402          usize,
403          gen_u32,
404          gen_mod_u32,
405          "Generates a random `isize` in the given range."
406      );
407      #[cfg(target_pointer_width = "64")]
408      rng_integer!(
409          isize,
410          usize,
411          gen_u64,
412          gen_mod_u64,
413          "Generates a random `isize` in the given range."
414      );
415  
416      /// Generates a random `char` in range a-z.
417      #[inline]
418      pub fn lowercase(&self) -> char {
419          const CHARS: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
420          let len = CHARS.len() as u8;
421          let i = self.u8(..len);
422          CHARS[i as usize] as char
423      }
424  
425      /// Initializes this generator with the given seed.
426      #[inline]
427      pub fn seed(&self, seed: u64) {
428          self.0.set(seed);
429      }
430  
431      /// Gives back **current** seed that is being held by this generator.
432      #[inline]
433      pub fn get_seed(&self) -> u64 {
434          self.0.get()
435      }
436  
437      /// Shuffles a slice randomly.
438      #[inline]
439      pub fn shuffle<T>(&self, slice: &mut [T]) {
440          for i in 1..slice.len() {
441              slice.swap(i, self.usize(..=i));
442          }
443      }
444  
445      /// Fill a byte slice with random data.
446      pub fn fill(&self, slice: &mut [u8]) {
447          // Filling the buffer in chunks of 8 is much faster.
448          let mut chunks = slice.chunks_exact_mut(8);
449          for chunk in chunks.by_ref() {
450              let n = self.gen_u64();
451              // Safe because the chunks are always 8 bytes exactly.
452              let bytes: &mut [u8; 8] = chunk.try_into().unwrap();
453              *bytes = n.to_ne_bytes();
454          }
455  
456          for item in chunks.into_remainder() {
457              *item = self.u8(..);
458          }
459      }
460  
461      rng_integer!(
462          u8,
463          u8,
464          gen_u32,
465          gen_mod_u32,
466          "Generates a random `u8` in the given range."
467      );
468  
469      rng_integer!(
470          u16,
471          u16,
472          gen_u32,
473          gen_mod_u32,
474          "Generates a random `u16` in the given range."
475      );
476  
477      rng_integer!(
478          u32,
479          u32,
480          gen_u32,
481          gen_mod_u32,
482          "Generates a random `u32` in the given range."
483      );
484  
485      rng_integer!(
486          u64,
487          u64,
488          gen_u64,
489          gen_mod_u64,
490          "Generates a random `u64` in the given range."
491      );
492  
493      rng_integer!(
494          u128,
495          u128,
496          gen_u128,
497          gen_mod_u128,
498          "Generates a random `u128` in the given range."
499      );
500  
501      #[cfg(target_pointer_width = "16")]
502      rng_integer!(
503          usize,
504          usize,
505          gen_u32,
506          gen_mod_u32,
507          "Generates a random `usize` in the given range."
508      );
509      #[cfg(target_pointer_width = "32")]
510      rng_integer!(
511          usize,
512          usize,
513          gen_u32,
514          gen_mod_u32,
515          "Generates a random `usize` in the given range."
516      );
517      #[cfg(target_pointer_width = "64")]
518      rng_integer!(
519          usize,
520          usize,
521          gen_u64,
522          gen_mod_u64,
523          "Generates a random `usize` in the given range."
524      );
525      #[cfg(target_pointer_width = "128")]
526      rng_integer!(
527          usize,
528          usize,
529          gen_u128,
530          gen_mod_u128,
531          "Generates a random `usize` in the given range."
532      );
533  
534      /// Generates a random `char` in range A-Z.
535      #[inline]
536      pub fn uppercase(&self) -> char {
537          const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
538          let len = CHARS.len() as u8;
539          let i = self.u8(..len);
540          CHARS[i as usize] as char
541      }
542  
543      /// Generates a random `char` in the given range.
544      ///
545      /// Panics if the range is empty.
546      #[inline]
547      pub fn char(&self, range: impl RangeBounds<char>) -> char {
548          use std::convert::TryFrom;
549  
550          let panic_empty_range = || {
551              panic!(
552                  "empty range: {:?}..{:?}",
553                  range.start_bound(),
554                  range.end_bound()
555              )
556          };
557  
558          let surrogate_start = 0xd800u32;
559          let surrogate_len = 0x800u32;
560  
561          let low = match range.start_bound() {
562              Bound::Unbounded => 0u8 as char,
563              Bound::Included(&x) => x,
564              Bound::Excluded(&x) => {
565                  let scalar = if x as u32 == surrogate_start - 1 {
566                      surrogate_start + surrogate_len
567                  } else {
568                      x as u32 + 1
569                  };
570                  char::try_from(scalar).unwrap_or_else(|_| panic_empty_range())
571              }
572          };
573  
574          let high = match range.end_bound() {
575              Bound::Unbounded => std::char::MAX,
576              Bound::Included(&x) => x,
577              Bound::Excluded(&x) => {
578                  let scalar = if x as u32 == surrogate_start + surrogate_len {
579                      surrogate_start - 1
580                  } else {
581                      (x as u32).wrapping_sub(1)
582                  };
583                  char::try_from(scalar).unwrap_or_else(|_| panic_empty_range())
584              }
585          };
586  
587          if low > high {
588              panic_empty_range();
589          }
590  
591          let gap = if (low as u32) < surrogate_start && (high as u32) >= surrogate_start {
592              surrogate_len
593          } else {
594              0
595          };
596          let range = high as u32 - low as u32 - gap;
597          let mut val = self.u32(0..=range) + low as u32;
598          if val >= surrogate_start {
599              val += gap;
600          }
601          val.try_into().unwrap()
602      }
603  }
604  
605  /// Initializes the thread-local generator with the given seed.
606  #[inline]
607  pub fn seed(seed: u64) {
608      RNG.with(|rng| rng.seed(seed))
609  }
610  
611  /// Gives back **current** seed that is being held by the thread-local generator.
612  #[inline]
613  pub fn get_seed() -> u64 {
614      RNG.with(|rng| rng.get_seed())
615  }
616  
617  /// Generates a random `bool`.
618  #[inline]
619  pub fn bool() -> bool {
620      RNG.with(|rng| rng.bool())
621  }
622  
623  /// Generates a random `char` in ranges a-z and A-Z.
624  #[inline]
625  pub fn alphabetic() -> char {
626      RNG.with(|rng| rng.alphabetic())
627  }
628  
629  /// Generates a random `char` in ranges a-z, A-Z and 0-9.
630  #[inline]
631  pub fn alphanumeric() -> char {
632      RNG.with(|rng| rng.alphanumeric())
633  }
634  
635  /// Generates a random `char` in range a-z.
636  #[inline]
637  pub fn lowercase() -> char {
638      RNG.with(|rng| rng.lowercase())
639  }
640  
641  /// Generates a random `char` in range A-Z.
642  #[inline]
643  pub fn uppercase() -> char {
644      RNG.with(|rng| rng.uppercase())
645  }
646  
647  /// Generates a random digit in the given `base`.
648  ///
649  /// Digits are represented by `char`s in ranges 0-9 and a-z.
650  ///
651  /// Panics if the base is zero or greater than 36.
652  #[inline]
653  pub fn digit(base: u32) -> char {
654      RNG.with(|rng| rng.digit(base))
655  }
656  
657  /// Shuffles a slice randomly.
658  #[inline]
659  pub fn shuffle<T>(slice: &mut [T]) {
660      RNG.with(|rng| rng.shuffle(slice))
661  }
662  
663  macro_rules! integer {
664      ($t:tt, $doc:tt) => {
665          #[doc = $doc]
666          ///
667          /// Panics if the range is empty.
668          #[inline]
669          pub fn $t(range: impl RangeBounds<$t>) -> $t {
670              RNG.with(|rng| rng.$t(range))
671          }
672      };
673  }
674  
675  integer!(u8, "Generates a random `u8` in the given range.");
676  integer!(i8, "Generates a random `i8` in the given range.");
677  integer!(u16, "Generates a random `u16` in the given range.");
678  integer!(i16, "Generates a random `i16` in the given range.");
679  integer!(u32, "Generates a random `u32` in the given range.");
680  integer!(i32, "Generates a random `i32` in the given range.");
681  integer!(u64, "Generates a random `u64` in the given range.");
682  integer!(i64, "Generates a random `i64` in the given range.");
683  integer!(u128, "Generates a random `u128` in the given range.");
684  integer!(i128, "Generates a random `i128` in the given range.");
685  integer!(usize, "Generates a random `usize` in the given range.");
686  integer!(isize, "Generates a random `isize` in the given range.");
687  integer!(char, "Generates a random `char` in the given range.");
688  
689  /// Generates a random `f32` in range `0..1`.
690  pub fn f32() -> f32 {
691      RNG.with(|rng| rng.f32())
692  }
693  
694  /// Generates a random `f64` in range `0..1`.
695  pub fn f64() -> f64 {
696      RNG.with(|rng| rng.f64())
697  }