Skip to content

Instantly share code, notes, and snippets.

@Lokathor
Created January 3, 2019 02:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Lokathor/e58e70df906ea9d58226904146a13915 to your computer and use it in GitHub Desktop.
Save Lokathor/e58e70df906ea9d58226904146a13915 to your computer and use it in GitHub Desktop.
//! 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(),
}
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment