[go: up one dir, main page]

randomize 2.0.0

A dead simple to use randomization library for rust.
//! Operations which rely on use of `std`. Not included by default.

use std::sync::{
  atomic::{AtomicPtr, Ordering},
  Mutex, MutexGuard,
};

/// Uses the system clock to get an arbitrary `u64` value.
pub fn u64_from_time() -> u64 {
  use std::time::{SystemTime, UNIX_EPOCH};

  let unix_delta = match SystemTime::now().duration_since(UNIX_EPOCH) {
    Ok(duration) => duration,
    Err(system_time_error) => system_time_error.duration(),
  };
  if unix_delta.subsec_nanos() != 0 {
    unix_delta.as_secs().wrapping_mul(unix_delta.subsec_nanos() as u64)
  } else {
    unix_delta.as_secs()
  }
}

/// Macro to declare a global generator of the desired type.
///
/// The generator type must implement From<u64>.
///
/// Give the name of the global (not very important), the generator type, and
/// the name of the getter you want to access the generator with.
///
/// ```rust
/// #[macro_use]
/// extern crate randomize;
///
/// make_global_generator!(GLOBAL_GEN, PCGu8Pick, get_global);
///
/// fn main() {
///   let gen: &mut PCGu8Pick = &mut get_global();
///   println!("{}", gen.next_rxs_m_xs());
/// }
/// ```
#[macro_export]
macro_rules! make_global_generator {
  ($global:ident, $generator:ty, $getter:ident) => {
    static $global: AtomicPtr<Mutex<$generator>> = AtomicPtr::new(null_mut());

    pub fn $getter() -> MutexGuard<'static, $generator> {
      let mutex_ref = match unsafe { $global.load(Ordering::SeqCst).as_ref() } {
        Some(mutex_ref) => mutex_ref,
        None => {
          let u = randomize::std::u64_from_time();
          let mutex_box_raw: *mut $generator = Box::into_raw(Box::new(Mutex::new($generator::from(u))));
          match unsafe { $global.compare_and_swap(null_mut(), mutex_box_raw, Ordering::SeqCst).as_ref() } {
            Some(mutex_ref) => {
              let _mutex_box_reconstructed = Box::from_raw(mutex_box_raw);
              mutex_ref
            }
            None => mutex_box_raw.as_ref().unwrap(),
          }
        }
      };
      match mutex_ref.lock() {
        Ok(guard) => guard,
        Err(poison_error_guard) => poison_error_guard.into_inner(),
      }
    }
  };
}