use crate::TypeInfo;
use std::any::Any;
use std::fmt;
use std::hash::{BuildHasherDefault, Hash, Hasher};
use std::rc::Rc;
pub trait ResourceKeyObject: Any {
fn as_any(&self) -> &dyn Any;
fn dyn_eq(&self, other: &dyn ResourceKeyObject) -> bool;
fn dyn_hash(&self, state: &mut dyn Hasher);
fn key_type_name(&self) -> &'static str;
}
impl<T: Eq + Hash + 'static> ResourceKeyObject for T {
fn as_any(&self) -> &dyn Any {
self
}
fn dyn_eq(&self, other: &dyn ResourceKeyObject) -> bool {
other.as_any().downcast_ref::<T>().is_some_and(|other| self == other)
}
fn dyn_hash(&self, mut state: &mut dyn Hasher) {
self.hash(&mut state)
}
fn key_type_name(&self) -> &'static str {
std::any::type_name::<T>()
}
}
#[derive(Clone)]
pub enum ResourceKey {
String(Rc<str>),
Type(&'static TypeInfo),
Object(Rc<dyn ResourceKeyObject>),
}
impl ResourceKey {
pub fn object<T: Eq + Hash + 'static>(value: T) -> Self {
ResourceKey::Object(Rc::new(value))
}
pub fn as_str(&self) -> Option<&str> {
match self {
ResourceKey::String(s) => Some(s),
_ => None,
}
}
}
impl PartialEq for ResourceKey {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(ResourceKey::String(a), ResourceKey::String(b)) => a == b,
(ResourceKey::Type(a), ResourceKey::Type(b)) => std::ptr::eq(*a, *b),
(ResourceKey::Object(a), ResourceKey::Object(b)) => (**a).dyn_eq(&**b),
_ => false,
}
}
}
impl Eq for ResourceKey {}
impl Hash for ResourceKey {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
ResourceKey::String(s) => {
state.write_u8(0);
s.hash(state)
}
ResourceKey::Type(t) => {
state.write_u8(1);
t.hash(state)
}
ResourceKey::Object(o) => {
state.write_u8(2);
(**o).dyn_hash(state)
}
}
}
}
impl fmt::Debug for ResourceKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for ResourceKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ResourceKey::String(s) => f.write_str(s),
ResourceKey::Type(t) => f.write_str(t.name()),
ResourceKey::Object(o) => f.write_str((**o).key_type_name()),
}
}
}
impl From<&str> for ResourceKey {
fn from(value: &str) -> Self {
ResourceKey::String(value.into())
}
}
impl From<String> for ResourceKey {
fn from(value: String) -> Self {
ResourceKey::String(value.into())
}
}
impl From<&'static TypeInfo> for ResourceKey {
fn from(value: &'static TypeInfo) -> Self {
ResourceKey::Type(value)
}
}
impl From<&ResourceKey> for ResourceKey {
fn from(value: &ResourceKey) -> Self {
value.clone()
}
}
#[derive(Clone, Copy, Default)]
pub(crate) struct ResourceKeyHasher {
hash: u64,
}
pub(crate) type ResourceKeyBuildHasher = BuildHasherDefault<ResourceKeyHasher>;
impl ResourceKeyHasher {
const MULTIPLIER: u64 = 0x51_7c_c1_b7_27_22_0a_95;
#[inline]
fn add(&mut self, word: u64) {
let product = (self.hash ^ word).wrapping_mul(Self::MULTIPLIER);
self.hash = product ^ (product >> 32);
}
}
impl Hasher for ResourceKeyHasher {
#[inline]
fn finish(&self) -> u64 {
self.hash
}
#[inline]
fn write(&mut self, bytes: &[u8]) {
let mut chunks = bytes.chunks_exact(8);
for chunk in &mut chunks {
let mut word = [0u8; 8];
word.copy_from_slice(chunk);
self.add(u64::from_le_bytes(word));
}
let rest = chunks.remainder();
if !rest.is_empty() {
let mut word = [0u8; 8];
word[..rest.len()].copy_from_slice(rest);
word[7] = rest.len() as u8;
self.add(u64::from_le_bytes(word));
}
}
#[inline]
fn write_u8(&mut self, i: u8) {
self.add(u64::from(i));
}
#[inline]
fn write_u16(&mut self, i: u16) {
self.add(u64::from(i));
}
#[inline]
fn write_u32(&mut self, i: u32) {
self.add(u64::from(i));
}
#[inline]
fn write_u64(&mut self, i: u64) {
self.add(i);
}
#[inline]
fn write_usize(&mut self, i: usize) {
self.add(i as u64);
}
}