#![cfg_attr(not(test), no_std)]
use core::ffi::CStr;
use core::str;
#[doc(hidden)]
pub mod wide;
#[doc(hidden)]
pub mod cfo;
mod murmur3;
pub use self::murmur3::murmur3;
mod pos;
pub use self::pos::position;
#[doc(hidden)]
pub mod xref;
#[macro_export]
macro_rules! random {
($ty:ident $(, $seeds:expr)* $(,)?) => {{
const _RANDOM: $ty = $crate::__random_cast!($ty,
$crate::entropy(concat!(file!(), ":", line!(), ":", column!() $(, ":", $seeds)*)));
_RANDOM
}};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __random_cast {
(u8, $seed:expr) => {
$seed as u8
};
(u16, $seed:expr) => {
$seed as u16
};
(u32, $seed:expr) => {
$seed as u32
};
(u64, $seed:expr) => {
$seed
};
(usize, $seed:expr) => {
$seed as usize
};
(i8, $seed:expr) => {
$seed as i8
};
(i16, $seed:expr) => {
$seed as i16
};
(i32, $seed:expr) => {
$seed as i32
};
(i64, $seed:expr) => {
$seed as i64
};
(isize, $seed:expr) => {
$seed as isize
};
(bool, $seed:expr) => {
$seed as i64 >= 0
};
(f32, $seed:expr) => {
unsafe {
::core::mem::transmute::<u32, f32>(
0b0_01111111 << (f32::MANTISSA_DIGITS - 1) | ($seed as u32 >> 9),
)
}
};
(f64, $seed:expr) => {
unsafe {
::core::mem::transmute::<u64, f64>(
0b0_01111111111 << (f64::MANTISSA_DIGITS - 1) | ($seed >> 12),
)
}
};
($ty:ident, $seed:expr) => {
compile_error!(concat!("unsupported type: ", stringify!($ty)))
};
}
#[test]
fn test_random_f32() {
#[track_caller]
fn t(v: f32) {
assert!(v >= 1.0 && v < 2.0, "{}", v);
}
use random as r;
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
t(r!(f32));
}
#[test]
fn test_random_f64() {
#[track_caller]
fn t(v: f64) {
assert!(v >= 1.0 && v < 2.0, "{}", v);
}
use random as r;
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
t(r!(f64));
}
#[inline(always)]
pub const fn splitmix(seed: u64) -> u64 {
let next = seed.wrapping_add(0x9e3779b97f4a7c15);
let mut z = next;
z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
return z ^ (z >> 31);
}
#[inline(always)]
pub const fn hash(s: &str) -> u32 {
let s = s.as_bytes();
let mut result = 3581u32;
let mut i = 0usize;
while i < s.len() {
result = result.wrapping_mul(33) ^ s[i] as u32;
i += 1;
}
return result;
}
#[macro_export]
macro_rules! hash {
($s:expr) => {{
const _DJB2_HASH: u32 = $crate::hash($s);
_DJB2_HASH
}};
}
#[doc(hidden)]
#[inline(always)]
pub const fn entropy(string: &str) -> u64 {
splitmix(SEED ^ splitmix(hash(string) as u64))
}
pub const SEED: u64 = splitmix(hash(match option_env!("OBFANY_SEED") {
Some(seed) => seed,
None => "FIXED",
}) as u64);
#[doc(hidden)]
pub mod bytes;
#[doc(hidden)]
pub mod words;
#[doc(hidden)]
#[inline(always)]
pub const fn unsafe_as_str(bytes: &[u8]) -> &str {
#[cfg(debug_assertions)]
return match str::from_utf8(bytes) {
Ok(s) => s,
Err(_) => panic!("invalid str"),
};
#[cfg(not(debug_assertions))]
return unsafe { str::from_utf8_unchecked(bytes) };
}
#[doc(hidden)]
#[inline(always)]
pub const fn unsafe_as_cstr(bytes: &[u8]) -> &CStr {
#[cfg(debug_assertions)]
return match CStr::from_bytes_with_nul(bytes) {
Ok(cstr) => cstr,
Err(_) => panic!("invalid cstr"),
};
#[cfg(not(debug_assertions))]
return unsafe { CStr::from_bytes_with_nul_unchecked(bytes) };
}