use std::{
hash::{BuildHasher, Hasher},
marker::PhantomData,
num::Wrapping,
};
use crate::span::Span;
#[cfg(not(any(miri, test)))]
xlang_host::rustcall! {
extern "rustcall"{
pub fn xlang_hash_bytes(x: Span<u8>) -> u64;
pub static XLANG_HASH_SEED: u8;
}
}
#[cfg(any(miri, test))]
xlang_host::rustcall! {
pub unsafe extern "rustcall" fn xlang_hash_bytes(x: Span<u8>) -> u64{
#[cfg(not(miri))]
static SEED: u64 = 14_695_981_039_346_656_037;
#[cfg(miri)]
static mut SEED: u64 = 0;
#[cfg(miri)]
{
static SEED_ONCE: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
if SEED_ONCE.load(std::sync::atomic::Ordering::Acquire)&1==0{
while (SEED_ONCE.fetch_or(0x100,std::sync::atomic::Ordering::Acquire)&0x100)!=0{}
if SEED_ONCE.load(std::sync::atomic::Ordering::Acquire)&1==0{
SEED = (&SEED_ONCE as *const _ as usize as u64)^14_695_981_039_346_656_037;
}
SEED_ONCE.store(0x1,std::sync::atomic::Ordering::Release); }
}
let mut hash = SEED;
for b in x{
hash ^= (*b) as u64;
hash =hash.wrapping_mul(PRIME);
}
hash
}
}
#[cfg(any(miri, test))]
pub static XLANG_HASH_SEED: u8 = 1;
#[repr(C)]
#[derive(Debug)]
pub struct XLangHasher(Wrapping<u64>);
#[repr(C)]
#[derive(Debug)]
pub struct BuildHasherDefault<H>(PhantomData<H>);
impl<H: Default + Hasher> BuildHasher for BuildHasherDefault<H> {
type Hasher = H;
fn build_hasher(&self) -> H {
Default::default()
}
}
impl<H> Clone for BuildHasherDefault<H> {
fn clone(&self) -> Self {
Self::default()
}
}
impl<H> Default for BuildHasherDefault<H> {
fn default() -> Self {
Self(PhantomData)
}
}
const PRIME: u64 = 1_099_511_628_211;
impl XLangHasher {
#[must_use]
pub const fn new() -> Self {
Self(Wrapping(14_695_981_039_346_656_037))
}
#[must_use]
pub const fn from_seed(seed: u64) -> Self {
Self(Wrapping(seed))
}
}
impl Hasher for XLangHasher {
fn finish(&self) -> u64 {
self.0 .0
}
fn write(&mut self, bytes: &[u8]) {
self.0 ^= Wrapping(unsafe { xlang_hash_bytes(Span::from(bytes)) });
self.0 *= Wrapping(PRIME);
}
fn write_u8(&mut self, i: u8) {
self.write(&[i]);
}
fn write_u16(&mut self, i: u16) {
self.write(&i.to_ne_bytes());
}
fn write_u32(&mut self, i: u32) {
self.write(&i.to_ne_bytes());
}
fn write_u64(&mut self, i: u64) {
self.write(&i.to_ne_bytes());
}
fn write_u128(&mut self, i: u128) {
self.write(&i.to_ne_bytes());
}
fn write_usize(&mut self, i: usize) {
self.write(&i.to_ne_bytes());
}
#[allow(clippy::cast_sign_loss)]
fn write_i8(&mut self, i: i8) {
self.write_u8(i as u8);
}
fn write_i16(&mut self, i: i16) {
self.write(&i.to_ne_bytes());
}
fn write_i32(&mut self, i: i32) {
self.write(&i.to_ne_bytes());
}
fn write_i64(&mut self, i: i64) {
self.write(&i.to_ne_bytes());
}
fn write_i128(&mut self, i: i128) {
self.write(&i.to_ne_bytes());
}
fn write_isize(&mut self, i: isize) {
self.write(&i.to_ne_bytes());
}
}
impl Default for XLangHasher {
fn default() -> Self {
Self::from_seed(unsafe { xlang_hash_bytes(Span::from_ref(&XLANG_HASH_SEED)) })
}
}