1#![warn(missing_docs)]
4
5const STATE_SIZE: usize = 4;
6
7type Target = u64;
8type StateType = [Target; STATE_SIZE];
9
10static mut STATE: StateType = [0, 0, 0, 0];
11
12pub fn get_state() -> StateType {
14 unsafe { STATE }
15}
16
17#[used]
18#[cfg_attr(target_os = "linux", link_section = ".init_array")]
19#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
20#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
21static INIT: extern "C" fn() = {
22 extern "C" fn init() {
23 unsafe {
24 use std::alloc::*;
25
26 let mut res = STATE;
27
28 const ALLOC: usize = STATE_SIZE * STATE_SIZE;
29
30 let layout = Layout::array::<Target>(ALLOC).unwrap();
31 let ptr = alloc(layout);
32
33 if ptr.is_null() {
34 handle_alloc_error(layout);
35 }
36
37 let garbage_arr = &mut *(ptr as *mut [Target; ALLOC]);
38
39 let addr = std::hint::black_box(ptr as Target);
41 let now = std::hint::black_box(
42 std::time::SystemTime::now()
43 .duration_since(std::time::UNIX_EPOCH)
44 .expect("to get system time")
45 .subsec_micros() as u64,
46 );
47 let now_bits = now ^ (now << 32) ^ (now.rotate_left(25));
48 let mut bits = addr ^ (addr >> 11) ^ (addr.rotate_right(30)) ^ now_bits;
49
50 for (i, garbage) in garbage_arr.iter_mut().enumerate() {
52 let current = &mut res[i % STATE_SIZE];
53
54 let mut val = std::hint::black_box(*garbage);
55 val ^= bits;
56
57 let msb = ((bits & 1) ^ ((bits >> 1) & 1)) << (Target::BITS - 1);
58 bits >>= 1;
59 bits |= msb;
60
61 *current ^= val;
62 std::ptr::write_volatile(garbage, val);
63 }
64
65 STATE = res;
66
67 dealloc(ptr, layout);
68 }
69 }
70
71 init
72};
73
74#[inline]
75fn xoshiro256pp() {
76 unsafe {
77 let s = STATE[1] << 17;
78
79 STATE[2] ^= STATE[0];
80 STATE[3] ^= STATE[1];
81 STATE[1] ^= STATE[2];
82 STATE[0] ^= STATE[3];
83
84 STATE[2] ^= s;
85
86 STATE[3] = STATE[3].rotate_left(45);
87 }
88}
89
90#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
92pub trait Random: Sized {
93 fn random() -> Self;
95}
96
97#[inline(always)]
112#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
113pub fn generate<T: Random>() -> T {
114 T::random()
115}
116
117macro_rules! make {
118 ($type: ident, $code: block) => {
119 #[doc = concat!("Will generate a random ", stringify!($type))]
120 #[doc = concat!("let a: ", stringify!($type), " = hel_random::", stringify!($type), "();")]
124 #[doc = concat!("let b: ", stringify!($type), " = hel_random::", stringify!($type), "();")]
125 #[doc = concat!("if std::mem::size_of::<", stringify!($type), ">() > 1 {")]
127 #[inline]
131 #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
132 pub fn $type() -> $type {
133 $code
134 }
135
136 impl Random for $type {
137 #[doc = concat!("Will generate a random ", stringify!($type))]
138 #[doc = concat!("let r = ", stringify!($type), "::random();")]
144 #[inline(always)]
147 fn random() -> Self {
148 $type()
149 }
150 }
151 };
152
153 ($type: ident) => {
154 make!($type, { u64() as $type });
155 };
156}
157
158make!(u128, {
159 xoshiro256pp();
160
161 unsafe {
162 STATE[0].wrapping_add(STATE[2]) as u128 | (((STATE[1]).wrapping_add(STATE[3]) as u128) << 64)
163 }
164});
165make!(i128, { u128() as i128 });
166
167make!(u64, {
168 xoshiro256pp();
169 unsafe {
170 STATE[0]
171 .wrapping_add(STATE[3])
172 .rotate_left(23)
173 .wrapping_add(STATE[0])
174 }
175});
176make!(i64);
177make!(u32);
178make!(i32);
179make!(u16);
180make!(i16);
181make!(u8);
182make!(i8);
183
184make!(bool, {
185 unsafe {
186 if STATE[0] == 0 {
188 return false;
189 }
190
191 loop {
192 xoshiro256pp();
193
194 let a = (STATE[0] & 1) == 1;
195 let b = (STATE[1] & 1) == 1;
196
197 if a != b {
198 return a;
199 }
200 }
201 }
202});
203
204