-
-
Save Ratysz/6c593581ac5a24003651a9d02a38a37b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::{ | |
any::Any, | |
collections::{hash_map::RandomState, HashMap}, | |
fmt::{Debug, Formatter, Result as FmtResult}, | |
hash::{BuildHasher, Hash, Hasher}, | |
}; | |
trait DynEq: Any { | |
fn as_any(&self) -> &dyn Any; | |
fn dyn_eq(&self, other: &dyn DynEq) -> bool; | |
} | |
impl<T> DynEq for T | |
where | |
T: Any + Eq, | |
{ | |
fn as_any(&self) -> &dyn Any { | |
self | |
} | |
fn dyn_eq(&self, other: &dyn DynEq) -> bool { | |
if let Some(other) = other.as_any().downcast_ref::<T>() { | |
return self == other; | |
} | |
false | |
} | |
} | |
trait DynHash: DynEq { | |
fn as_dyn_eq(&self) -> &dyn DynEq; | |
fn dyn_hash(&self, state: &mut dyn Hasher); | |
} | |
impl<T> DynHash for T | |
where | |
T: DynEq + Hash, | |
{ | |
fn as_dyn_eq(&self) -> &dyn DynEq { | |
self | |
} | |
fn dyn_hash(&self, mut state: &mut dyn Hasher) { | |
T::hash(self, &mut state); | |
self.type_id().hash(&mut state); | |
} | |
} | |
impl PartialEq for dyn DynHash { | |
fn eq(&self, other: &dyn DynHash) -> bool { | |
self.dyn_eq(other.as_dyn_eq()) | |
} | |
} | |
impl Eq for dyn DynHash {} | |
impl Hash for dyn DynHash { | |
fn hash<H: Hasher>(&self, state: &mut H) { | |
self.dyn_hash(state); | |
} | |
} | |
trait AnyKey: DynHash + Debug {} | |
impl<T> AnyKey for T where T: DynHash + Debug {} | |
impl PartialEq for dyn AnyKey { | |
fn eq(&self, other: &Self) -> bool { | |
self.dyn_eq(other.as_dyn_eq()) | |
} | |
} | |
impl Eq for dyn AnyKey {} | |
impl Hash for dyn AnyKey { | |
fn hash<H: Hasher>(&self, state: &mut H) { | |
self.dyn_hash(state); | |
} | |
} | |
pub struct AnyKeyHashMap<V, S = RandomState> { | |
inner: HashMap<Box<dyn AnyKey>, V, S>, | |
} | |
impl<V, S> Default for AnyKeyHashMap<V, S> | |
where | |
S: Default, | |
{ | |
fn default() -> Self { | |
Self { | |
inner: Default::default(), | |
} | |
} | |
} | |
impl<V> AnyKeyHashMap<V, RandomState> { | |
pub fn new() -> Self { | |
Self::default() | |
} | |
pub fn with_capacity(capacity: usize) -> Self { | |
Self { | |
inner: HashMap::with_capacity(capacity), | |
} | |
} | |
} | |
impl<V, S> AnyKeyHashMap<V, S> | |
where | |
S: BuildHasher, | |
{ | |
pub fn with_hasher(hash_builder: S) -> Self { | |
Self { | |
inner: HashMap::with_hasher(hash_builder), | |
} | |
} | |
pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { | |
Self { | |
inner: HashMap::with_capacity_and_hasher(capacity, hash_builder), | |
} | |
} | |
pub fn debug_iter(&self) -> impl Iterator<Item = (&dyn Debug, &V)> { | |
self.inner | |
.iter() | |
.map(|(key, value)| (key as &dyn Debug, value)) | |
} | |
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> { | |
self.inner.values_mut() | |
} | |
pub fn get(&self, key: &(impl Any + Eq + Hash + Debug)) -> Option<&V> { | |
self.inner.get(key as &dyn AnyKey) | |
} | |
pub fn contains_key(&self, key: &(impl Any + Eq + Hash + Debug)) -> bool { | |
self.inner.contains_key(key as &dyn AnyKey) | |
} | |
pub fn insert(&mut self, key: impl Any + Eq + Hash + Debug, value: V) -> Option<V> { | |
self.inner.insert(Box::new(key) as Box<dyn AnyKey>, value) | |
} | |
pub fn remove(&mut self, key: &(impl Any + Eq + Hash + Debug)) -> Option<V> { | |
self.inner.remove(key as &dyn AnyKey) | |
} | |
} | |
impl<V, S> Debug for AnyKeyHashMap<V, S> | |
where | |
V: Debug, | |
S: BuildHasher, | |
{ | |
fn fmt(&self, f: &mut Formatter) -> FmtResult { | |
self.inner.fmt(f) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment