#![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) => {
f32::from_bits(0b0_01111111 << (f32::MANTISSA_DIGITS - 1) | ($seed as u32 >> 9))
};
(f64, $seed:expr) => {
f64::from_bits(0b0_01111111111 << (f64::MANTISSA_DIGITS - 1) | ($seed >> 12))
};
($ty:ident, $seed:expr) => {
compile_error!(concat!("unsupported type: ", stringify!($ty)))
};
}
#[test]
fn test_random_f32() {
fn t(v: f32) {
assert!(v >= 1.0 && v < 2.0, "{}", v);
}
t(random!(f32, "a"));
t(random!(f32, "b"));
t(random!(f32, "c"));
t(random!(f32));
}
#[test]
fn test_random_f64() {
fn t(v: f64) {
assert!(v >= 1.0 && v < 2.0, "{}", v);
}
t(random!(f64, "a"));
t(random!(f64, "b"));
t(random!(f64, "c"));
t(random!(f64));
}
#[test]
fn test_random_int_types() {
let _: u8 = random!(u8, "u8");
let _: u16 = random!(u16, "u16");
let _: u32 = random!(u32, "u32");
let _: u64 = random!(u64, "u64");
let _: usize = random!(usize, "usize");
let _: i8 = random!(i8, "i8");
let _: i16 = random!(i16, "i16");
let _: i32 = random!(i32, "i32");
let _: i64 = random!(i64, "i64");
let _: isize = random!(isize, "isize");
let _: bool = random!(bool, "bool");
assert_ne!(random!(u64, "x"), random!(u64, "y"));
}
#[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);
}
#[test]
fn test_splitmix() {
assert_ne!(splitmix(0), 0);
assert_eq!(splitmix(42), splitmix(42));
assert_ne!(splitmix(1), splitmix(2));
}
#[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;
}
#[test]
fn test_hash() {
assert_eq!(hash!("Hello World"), 0x6E4A573D);
let _ = hash!("");
let _ = hash!("🦀");
assert_eq!(hash!("abc"), hash!("abc"));
assert_ne!(hash!("abc"), hash!("abd"));
}
#[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) };
}