use crate::{key::DynKey, make_concrete::MakeConcrete};
use std::{
collections::HashMap,
hash::{Hash, RandomState},
ops::{Deref, DerefMut},
};
#[derive(Debug, Clone, Default)]
pub struct HashDynMap<K, DynT, S = RandomState>
where
DynT: ?Sized,
{
inner: HashMap<K, Box<DynT>, S>,
}
impl<K, DynT> HashDynMap<K, DynT>
where
DynT: ?Sized,
{
pub fn new() -> Self {
Self {
inner: HashMap::new(),
}
}
}
impl<K, DynT: ?Sized, S> HashDynMap<K, DynT, S> {
pub fn with_hasher(hash_state: S) -> Self {
Self {
inner: HashMap::with_hasher(hash_state),
}
}
}
impl<K, DynT> HashDynMap<K, DynT>
where
DynT: ?Sized,
K: Hash + Eq + Clone,
{
pub fn insert<T>(&mut self, key: K, value: T) -> Result<DynKey<K, T>, T>
where
DynT: MakeConcrete<T>,
{
if self.inner.contains_key(&key) {
return Err(value);
}
self.inner.insert(key.clone(), DynT::from_concrete(value));
unsafe { Ok(DynKey::new(key)) }
}
pub unsafe fn insert_overwrite<T>(&mut self, key: K, value: T) -> DynKey<K, T>
where
DynT: MakeConcrete<T>,
{
self.inner.insert(key.clone(), DynT::from_concrete(value));
unsafe { DynKey::new(key) }
}
pub fn get<T>(&self, key: &DynKey<K, T>) -> Option<&T>
where
DynT: MakeConcrete<T>,
{
let dyn_value = self.inner.get(key.key())?;
Some(unsafe { dyn_value.as_concrete() })
}
pub fn get_mut<T>(&mut self, key: &DynKey<K, T>) -> Option<&mut T>
where
DynT: MakeConcrete<T>,
{
let dyn_value = self.inner.get_mut(key.key())?;
Some(unsafe { dyn_value.as_concrete_mut() })
}
pub fn get_dyn(&self, key: &K) -> Option<&DynT> {
self.inner.get(key).map(|v| v.deref())
}
pub fn get_dyn_mut(&mut self, key: &K) -> Option<&mut DynT> {
self.inner.get_mut(key).map(|v| v.deref_mut())
}
pub fn iter(&self) -> impl Iterator<Item = (&K, &Box<DynT>)> {
self.inner.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut Box<DynT>)> {
self.inner.iter_mut()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn remove<T>(&mut self, key: &DynKey<K, T>) -> Option<Box<T>>
where
DynT: MakeConcrete<T>,
{
let dyn_value: Box<DynT> = self.inner.remove(key.key())?;
unsafe {
let ref_value = &mut *Box::into_raw(dyn_value);
let ref_value = DynT::as_concrete_mut(ref_value) as *mut T;
Some(Box::from_raw(ref_value))
}
}
pub fn remove_dyn(&mut self, key: &K) -> Option<Box<DynT>> {
self.inner.remove(key)
}
pub fn clear(&mut self) {
self.inner.clear();
}
pub fn contains_key(&self, key: &K) -> bool {
self.inner.contains_key(key)
}
}
impl<K, DynT: ?Sized> IntoIterator for HashDynMap<K, DynT> {
type Item = (K, Box<DynT>);
type IntoIter = std::collections::hash_map::IntoIter<K, Box<DynT>>;
fn into_iter(self) -> Self::IntoIter {
self.inner.into_iter()
}
}
#[cfg(test)]
mod test {
use super::HashDynMap;
use crate::dynamify;
#[test]
fn test_valid_value() {
trait Test {
fn message(&self) -> &'static str;
}
#[derive(Debug)]
struct Hello;
impl Hello {
fn hello_own_fn(&self) -> &'static str {
"Hello, I'm concrete `Hello` instance"
}
}
impl Test for Hello {
fn message(&self) -> &'static str {
"Hello"
}
}
#[derive(Debug)]
struct World;
impl World {
fn world_own_fn(&self) -> &'static str {
"World, I'm concrete `World` instance"
}
}
impl Test for World {
fn message(&self) -> &'static str {
"World"
}
}
dynamify!(Test);
let mut dynmap: HashDynMap<&'static str, dyn Test> = HashDynMap::new();
let hello_key = dynmap.insert("hello", Hello).unwrap();
let world_key = dynmap.insert("world", World).unwrap();
assert_eq!(
dynmap.get(&hello_key).unwrap().hello_own_fn(),
"Hello, I'm concrete `Hello` instance"
);
assert_eq!(
dynmap.get(&world_key).unwrap().world_own_fn(),
"World, I'm concrete `World` instance"
);
}
}