#![warn(missing_docs)]
const STATE_SIZE: usize = 4;
type Target = u64;
type StateType = [Target; STATE_SIZE];
static mut STATE: StateType = [0, 0, 0, 0];
pub fn get_state() -> StateType {
unsafe { STATE }
}
#[used]
#[cfg_attr(target_os = "linux", link_section = ".init_array")]
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
static INIT: extern "C" fn() = {
extern "C" fn init() {
unsafe {
use std::alloc::*;
let mut res = STATE;
const ALLOC: usize = STATE_SIZE * STATE_SIZE;
let layout = Layout::array::<Target>(ALLOC).unwrap();
let ptr = alloc(layout);
if ptr.is_null() {
handle_alloc_error(layout);
}
let garbage_arr = &mut *(ptr as *mut [Target; ALLOC]);
let addr = std::hint::black_box(ptr as Target);
let now = std::hint::black_box(
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.expect("to get system time")
.subsec_micros() as u64,
);
let now_bits = now ^ (now << 32) ^ (now.rotate_left(25));
let mut bits = addr ^ (addr >> 11) ^ (addr.rotate_right(30)) ^ now_bits;
for (i, garbage) in garbage_arr.iter_mut().enumerate() {
let current = &mut res[i % STATE_SIZE];
let mut val = std::hint::black_box(*garbage);
val ^= bits;
let msb = ((bits & 1) ^ ((bits >> 1) & 1)) << (Target::BITS - 1);
bits >>= 1;
bits |= msb;
*current ^= val;
std::ptr::write_volatile(garbage, val);
}
STATE = res;
dealloc(ptr, layout);
}
}
init
};
#[inline]
fn xoshiro256pp() {
unsafe {
let s = STATE[1] << 17;
STATE[2] ^= STATE[0];
STATE[3] ^= STATE[1];
STATE[1] ^= STATE[2];
STATE[0] ^= STATE[3];
STATE[2] ^= s;
STATE[3] = STATE[3].rotate_left(45);
}
}
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
pub trait Random: Sized {
fn random() -> Self;
}
#[inline(always)]
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
pub fn generate<T: Random>() -> T {
T::random()
}
macro_rules! make {
($type: ident, $code: block) => {
#[doc = concat!("Will generate a random ", stringify!($type))]
#[doc = concat!("let a: ", stringify!($type), " = hel_random::", stringify!($type), "();")]
#[doc = concat!("let b: ", stringify!($type), " = hel_random::", stringify!($type), "();")]
#[doc = concat!("if std::mem::size_of::<", stringify!($type), ">() > 1 {")]
#[inline]
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
pub fn $type() -> $type {
$code
}
impl Random for $type {
#[doc = concat!("Will generate a random ", stringify!($type))]
#[doc = concat!("let r = ", stringify!($type), "::random();")]
#[inline(always)]
fn random() -> Self {
$type()
}
}
};
($type: ident) => {
make!($type, { u64() as $type });
};
}
make!(u128, {
xoshiro256pp();
unsafe {
STATE[0].wrapping_add(STATE[2]) as u128 | (((STATE[1]).wrapping_add(STATE[3]) as u128) << 64)
}
});
make!(i128, { u128() as i128 });
make!(u64, {
xoshiro256pp();
unsafe {
STATE[0]
.wrapping_add(STATE[3])
.rotate_left(23)
.wrapping_add(STATE[0])
}
});
make!(i64);
make!(u32);
make!(i32);
make!(u16);
make!(i16);
make!(u8);
make!(i8);
make!(bool, {
unsafe {
if STATE[0] == 0 {
return false;
}
loop {
xoshiro256pp();
let a = (STATE[0] & 1) == 1;
let b = (STATE[1] & 1) == 1;
if a != b {
return a;
}
}
}
});