use crate::{Component, ValueType};
use std::any;
use std::fmt;
use std::hash;
use std::hash::{BuildHasher as _, BuildHasherDefault, Hash as _, Hasher as _};
use std::mem;
use twox_hash::XxHash64;
const SEP: usize = 0x7f;
const TYPE: usize = 1;
const INSTANCE_FUNCTION: usize = 2;
const GETTER: usize = 3;
const OBJECT_KEYS: usize = 4;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Hash(u64);
impl Hash {
pub(crate) const fn new(hash: u64) -> Self {
Self(hash)
}
pub fn from_any<T>() -> Self
where
T: any::Any,
{
Self::from_type_id(any::TypeId::of::<T>())
}
pub fn from_type_id(type_id: any::TypeId) -> Self {
unsafe { mem::transmute(type_id) }
}
pub fn instance_function<N>(value_type: ValueType, name: N) -> Self
where
N: IntoHash,
{
let name = name.into_hash();
Self(Hash::of((INSTANCE_FUNCTION, value_type, SEP, name)).0)
}
pub fn getter<N>(value_type: ValueType, name: N) -> Self
where
N: IntoHash,
{
let name = name.into_hash();
Self(Hash::of((GETTER, value_type, SEP, name)).0)
}
pub fn of<T: hash::Hash>(thing: T) -> Self {
let mut hasher = Self::new_hasher();
thing.hash(&mut hasher);
Self(hasher.finish())
}
pub fn object_keys<I>(keys: I) -> Self
where
I: IntoIterator,
I::Item: AsRef<str>,
{
let mut hasher = Self::new_hasher();
OBJECT_KEYS.hash(&mut hasher);
for key in keys {
SEP.hash(&mut hasher);
key.as_ref().hash(&mut hasher);
}
Self(hasher.finish())
}
pub fn type_hash<I>(path: I) -> Self
where
I: IntoHash,
{
path.into_hash()
}
fn new_hasher() -> impl hash::Hasher {
BuildHasherDefault::<XxHash64>::default().build_hasher()
}
fn path_hash<I>(kind: usize, path: I) -> Self
where
I: IntoIterator,
I::Item: Into<Component>,
{
let mut hasher = Self::new_hasher();
kind.hash(&mut hasher);
for part in path {
part.into().hash(&mut hasher);
}
Self(hasher.finish())
}
}
impl fmt::Display for Hash {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "0x{:x}", self.0)
}
}
impl fmt::Debug for Hash {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "Hash(0x{:x})", self.0)
}
}
pub trait IntoHash {
fn into_hash(self) -> Hash;
}
impl IntoHash for Hash {
fn into_hash(self) -> Hash {
self
}
}
impl<I> IntoHash for I
where
I: IntoIterator,
I::Item: Into<Component>,
{
fn into_hash(self) -> Hash {
Hash::path_hash(TYPE, self)
}
}