use std::{
any::{Any, TypeId},
fmt,
hash::{Hash, Hasher},
sync::atomic::{AtomicU64, Ordering},
};
static NEXT_UNIQUE_KEY: AtomicU64 = AtomicU64::new(1);
fn next_unique_key() -> u64 {
NEXT_UNIQUE_KEY
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |id| id.checked_add(1))
.expect("unique key identity space exhausted")
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct KeyId {
type_id: TypeId,
hash: u64,
}
impl KeyId {
#[must_use]
pub const fn type_id(self) -> TypeId {
self.type_id
}
#[must_use]
pub const fn hash(self) -> u64 {
self.hash
}
}
pub trait Key: Any + fmt::Debug {
fn key_id(&self) -> KeyId;
fn eq_key(&self, other: &dyn Key) -> bool;
fn clone_box(&self) -> Box<dyn Key>;
fn as_any(&self) -> &dyn Any;
}
pub trait LocalKey: Key {}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct UniqueKey(u64);
impl UniqueKey {
#[must_use]
pub fn new() -> Self {
Self(next_unique_key())
}
#[must_use]
pub const fn id(self) -> u64 {
self.0
}
}
impl Default for UniqueKey {
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for UniqueKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("UniqueKey").field(&self.0).finish()
}
}
impl Key for UniqueKey {
fn key_id(&self) -> KeyId {
KeyId {
type_id: TypeId::of::<Self>(),
hash: self.0,
}
}
fn eq_key(&self, other: &dyn Key) -> bool {
other
.as_any()
.downcast_ref::<Self>()
.is_some_and(|other| self == other)
}
fn clone_box(&self) -> Box<dyn Key> {
Box::new(*self)
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl LocalKey for UniqueKey {}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ValueKey<T>(pub T);
impl<T> ValueKey<T> {
#[must_use]
pub const fn new(value: T) -> Self {
Self(value)
}
#[must_use]
pub const fn value(&self) -> &T {
&self.0
}
}
impl<T> Key for ValueKey<T>
where
T: Any + Clone + Eq + Hash + fmt::Debug,
{
fn key_id(&self) -> KeyId {
let mut hasher = std::collections::hash_map::DefaultHasher::new();
self.hash(&mut hasher);
KeyId {
type_id: TypeId::of::<Self>(),
hash: hasher.finish(),
}
}
fn eq_key(&self, other: &dyn Key) -> bool {
other
.as_any()
.downcast_ref::<Self>()
.is_some_and(|other| self == other)
}
fn clone_box(&self) -> Box<dyn Key> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl<T> LocalKey for ValueKey<T> where T: Any + Clone + Eq + Hash + fmt::Debug {}
pub type StringKey = ValueKey<String>;
pub type KeyObject<T> = ValueKey<T>;
pub struct KeyHandle(Box<dyn Key>);
impl KeyHandle {
#[must_use]
pub fn new<K>(key: K) -> Self
where
K: Key,
{
Self(Box::new(key))
}
#[must_use]
pub fn as_key(&self) -> &dyn Key {
&*self.0
}
#[must_use]
pub fn key_id(&self) -> KeyId {
self.0.key_id()
}
}
impl Clone for KeyHandle {
fn clone(&self) -> Self {
Self(self.0.clone_box())
}
}
impl fmt::Debug for KeyHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("KeyHandle").field(&self.0).finish()
}
}
impl PartialEq for KeyHandle {
fn eq(&self, other: &Self) -> bool {
self.0.eq_key(&*other.0)
}
}
impl Eq for KeyHandle {}
impl Hash for KeyHandle {
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&self.key_id(), state);
}
}
impl Key for KeyHandle {
fn key_id(&self) -> KeyId {
self.0.key_id()
}
fn eq_key(&self, other: &dyn Key) -> bool {
other
.as_any()
.downcast_ref::<Self>()
.is_some_and(|other| self == other)
}
fn clone_box(&self) -> Box<dyn Key> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl LocalKey for KeyHandle {}
impl From<String> for KeyHandle {
fn from(value: String) -> Self {
Self::new(StringKey::new(value))
}
}
impl From<&str> for KeyHandle {
fn from(value: &str) -> Self {
Self::new(StringKey::new(value.to_owned()))
}
}
impl From<UniqueKey> for KeyHandle {
fn from(value: UniqueKey) -> Self {
Self::new(value)
}
}
impl<T> From<ValueKey<T>> for KeyHandle
where
T: Any + Clone + Eq + Hash + fmt::Debug,
{
fn from(value: ValueKey<T>) -> Self {
Self::new(value)
}
}