use std::collections::HashMap;
use std::fmt::Formatter;
use std::hash::{BuildHasher, Hash};
use std::iter::FusedIterator;
use std::{any::Any, fmt::Debug, ops::Index};
use std::{collections::hash_map::RandomState, marker::PhantomData};
use crate::bounds::{AnyBounds, Bounds, HasBounds};
use crate::entry;
use crate::typedkey::{Key, TypedKey, TypedKeyRef};
use crate::typedvalue::TypedMapValue;
pub trait TypedMapKey<Marker = ()>: Eq + Hash {
type Value: 'static;
}
const INVALID_KEY: &str = "Broken TypedMap: invalid key type";
const INVALID_VALUE: &str = "Broken TypedMap: invalid value type";
pub struct TypedMap<Marker = (), KB: Bounds = AnyBounds, VB: Bounds = AnyBounds, S = RandomState> {
state: HashMap<TypedKey<KB>, TypedMapValue<VB>, S>,
_phantom: PhantomData<Marker>,
}
impl<Marker> TypedMap<Marker> {
pub fn new() -> Self {
TypedMap::new_with_bounds()
}
pub fn with_capacity(capacity: usize) -> Self {
TypedMap {
state: HashMap::with_capacity(capacity),
_phantom: PhantomData,
}
}
}
impl<Marker, KB, VB> TypedMap<Marker, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
pub fn new_with_bounds() -> Self {
TypedMap {
state: Default::default(),
_phantom: PhantomData,
}
}
}
impl<Marker, KB, VB, S> TypedMap<Marker, KB, VB, S>
where
S: BuildHasher,
KB: 'static + Bounds,
VB: 'static + Bounds,
{
pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self {
TypedMap {
state: HashMap::with_capacity_and_hasher(capacity, hash_builder),
_phantom: PhantomData,
}
}
pub fn with_hasher(hash_builder: S) -> Self {
TypedMap {
state: HashMap::with_hasher(hash_builder),
_phantom: PhantomData,
}
}
pub fn insert<K>(&mut self, key: K, value: K::Value) -> Option<K::Value>
where
KB: HasBounds<K>,
VB: HasBounds<K::Value>,
K: 'static + TypedMapKey<Marker>,
{
let typed_key = TypedKey::from_key(key);
let value = TypedMapValue::from_value(value);
let old_value = self.state.insert(typed_key, value);
old_value.and_then(|v| v.downcast::<K::Value>().ok())
}
pub fn insert_key_value(
&mut self,
key_value: TypedKeyValue<Marker, KB, VB>,
) -> Option<TypedKeyValue<Marker, KB, VB>> {
let entry = self.state.remove_entry(&key_value.key);
self.state.insert(key_value.key, key_value.value);
let (key, value) = entry?;
Some(TypedKeyValue {
key,
value,
_marker: PhantomData,
})
}
pub fn get<K>(&self, key: &K) -> Option<&K::Value>
where
KB: HasBounds<K>,
VB: HasBounds<K::Value>,
K: 'static + TypedMapKey<Marker>,
{
let typed_key = TypedKeyRef::from_key_ref(key);
let value = self.state.get(&typed_key as &dyn Key)?;
Some(value.downcast_ref::<K::Value>().expect(INVALID_VALUE))
}
pub fn get_mut<K>(&mut self, key: &K) -> Option<&mut K::Value>
where
KB: HasBounds<K>,
VB: HasBounds<K::Value>,
K: 'static + TypedMapKey<Marker>,
{
let typed_key = TypedKeyRef::from_key_ref(key);
let value = self.state.get_mut(&typed_key as &dyn Key)?;
Some(value.downcast_mut::<K::Value>().expect(INVALID_VALUE))
}
pub fn get_key_value<K>(&self, key: &K) -> Option<(&K, &K::Value)>
where
KB: HasBounds<K>,
VB: HasBounds<K::Value>,
K: 'static + TypedMapKey<Marker>,
{
let typed_key = TypedKeyRef::from_key_ref(key);
let (key, value) = self.state.get_key_value(&typed_key as &dyn Key)?;
Some((
key.downcast_ref().expect(INVALID_KEY),
value.downcast_ref().expect(INVALID_VALUE),
))
}
pub fn remove<K>(&mut self, key: &K) -> Option<K::Value>
where
KB: HasBounds<K>,
VB: HasBounds<K::Value>,
K: 'static + TypedMapKey<Marker>,
{
let typed_key = TypedKeyRef::from_key_ref(key);
let value = self.state.remove(&typed_key as &dyn Key)?;
Some(value.downcast::<K::Value>().expect(INVALID_VALUE))
}
pub fn remove_entry<K>(&mut self, key: &K) -> Option<(K, K::Value)>
where
KB: HasBounds<K>,
VB: HasBounds<K::Value>,
K: 'static + TypedMapKey<Marker>,
{
let typed_key = TypedKeyRef::from_key_ref(key);
let value = self.state.remove_entry(&typed_key as &dyn Key);
value.map(|(k, v)| {
let k = k.downcast::<K>().expect(INVALID_KEY);
let v = v.downcast::<K::Value>().expect(INVALID_VALUE);
(k, v)
})
}
pub fn entry<K>(&mut self, key: K) -> entry::Entry<'_, K, KB, VB, Marker>
where
KB: HasBounds<K>,
VB: HasBounds<K::Value>,
K: 'static + TypedMapKey<Marker>,
{
let typed_key = TypedKey::from_key(key);
entry::map_entry(self.state.entry(typed_key))
}
pub fn contains_key<K>(&self, key: &K) -> bool
where
KB: HasBounds<K>,
VB: HasBounds<K::Value>,
K: 'static + TypedMapKey<Marker>,
{
self.get(key).is_some()
}
pub fn len(&self) -> usize {
self.state.len()
}
pub fn capacity(&self) -> usize {
self.state.capacity()
}
pub fn is_empty(&self) -> bool {
self.state.is_empty()
}
pub fn clear(&mut self) {
self.state.clear();
}
pub fn reserve(&mut self, additional: usize) {
self.state.reserve(additional)
}
pub fn shrink_to_fit(&mut self) {
self.state.shrink_to_fit();
}
pub fn hasher(&self) -> &S {
self.state.hasher()
}
pub fn keys(&self) -> Keys<'_, KB, VB> {
Keys(self.state.keys())
}
pub fn values(&self) -> Values<'_, KB, VB> {
Values(self.state.values())
}
pub fn values_mut(&mut self) -> ValuesMut<'_, KB, VB> {
ValuesMut(self.state.values_mut())
}
pub fn drain(&mut self) -> Drain<'_, Marker, KB, VB> {
Drain(self.state.drain(), PhantomData)
}
pub fn iter(&self) -> Iter<'_, Marker, KB, VB> {
Iter(self.state.iter(), PhantomData)
}
pub fn iter_mut(&mut self) -> IterMut<'_, Marker, KB, VB> {
IterMut(self.state.iter_mut(), PhantomData)
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(TypedKeyValueMutRef<'_, Marker, KB, VB>) -> bool,
{
let g = move |key: &TypedKey<KB>, value: &mut TypedMapValue<VB>| {
f(TypedKeyValueMutRef {
key,
value,
_marker: PhantomData,
})
};
self.state.retain(g)
}
}
impl<Marker, KB, VB> Default for TypedMap<Marker, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
fn default() -> Self {
TypedMap::new_with_bounds()
}
}
impl<Marker, KB, VB> Debug for TypedMap<Marker, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("TypedMap")
}
}
impl<Marker, KB, VB, S> IntoIterator for TypedMap<Marker, KB, VB, S>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
S: BuildHasher,
{
type Item = TypedKeyValue<Marker, KB, VB>;
type IntoIter = IntoIter<Marker, KB, VB>;
fn into_iter(self) -> Self::IntoIter {
IntoIter(self.state.into_iter(), PhantomData)
}
}
impl<Marker, K, S, KB, VB> Index<&K> for TypedMap<Marker, KB, VB, S>
where
K: 'static + TypedMapKey<Marker>,
S: BuildHasher,
KB: 'static + Bounds + HasBounds<K>,
VB: 'static + Bounds + HasBounds<K::Value>,
{
type Output = K::Value;
fn index(&self, key: &K) -> &K::Value {
self.get(key).expect("no entry found for key")
}
}
#[derive(Clone)]
pub struct Iter<'a, Marker, KB: 'static + Bounds, VB: 'static + Bounds>(
std::collections::hash_map::Iter<'a, TypedKey<KB>, TypedMapValue<VB>>,
PhantomData<Marker>,
);
impl<'a, Marker, KB, VB> Iterator for Iter<'a, Marker, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
type Item = TypedKeyValueRef<'a, Marker, KB, VB>;
fn next(&mut self) -> Option<Self::Item> {
let (key, value) = self.0.next()?;
Some(TypedKeyValueRef {
key,
value,
_marker: PhantomData,
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<Marker, KB, VB> ExactSizeIterator for Iter<'_, Marker, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
}
impl<Marker, KB, VB> FusedIterator for Iter<'_, Marker, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
}
pub struct IterMut<'a, Marker, KB: 'static + Bounds, VB: 'static + Bounds>(
std::collections::hash_map::IterMut<'a, TypedKey<KB>, TypedMapValue<VB>>,
PhantomData<Marker>,
);
impl<'a, Marker, KB, VB> Iterator for IterMut<'a, Marker, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
type Item = TypedKeyValueMutRef<'a, Marker, KB, VB>;
fn next(&mut self) -> Option<Self::Item> {
let (key, value) = self.0.next()?;
Some(TypedKeyValueMutRef {
key,
value,
_marker: PhantomData,
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<Marker, KB, VB> ExactSizeIterator for IterMut<'_, Marker, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
}
impl<Marker, KB, VB> FusedIterator for IterMut<'_, Marker, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
}
pub struct Drain<'a, Marker, KB: 'static + Bounds, VB: 'static + Bounds>(
std::collections::hash_map::Drain<'a, TypedKey<KB>, TypedMapValue<VB>>,
PhantomData<Marker>,
);
impl<Marker, KB: 'static + Bounds, VB: 'static + Bounds> Iterator for Drain<'_, Marker, KB, VB> {
type Item = TypedKeyValue<Marker, KB, VB>;
fn next(&mut self) -> Option<Self::Item> {
let (key, value) = self.0.next()?;
Some(TypedKeyValue {
key,
value,
_marker: PhantomData,
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<Marker, KB: 'static + Bounds, VB: 'static + Bounds> ExactSizeIterator
for Drain<'_, Marker, KB, VB>
{
}
impl<Marker, KB: 'static + Bounds, VB: 'static + Bounds> FusedIterator
for Drain<'_, Marker, KB, VB>
{
}
pub struct IntoIter<Marker, KB: 'static + Bounds, VB: 'static + Bounds>(
std::collections::hash_map::IntoIter<TypedKey<KB>, TypedMapValue<VB>>,
PhantomData<Marker>,
);
impl<Marker, KB, VB> Iterator for IntoIter<Marker, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
type Item = TypedKeyValue<Marker, KB, VB>;
fn next(&mut self) -> Option<Self::Item> {
let (key, value) = self.0.next()?;
Some(TypedKeyValue {
key,
value,
_marker: PhantomData,
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<Marker, KB, VB> ExactSizeIterator for IntoIter<Marker, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
}
impl<Marker, KB, VB> FusedIterator for IntoIter<Marker, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
}
#[derive(Clone)]
pub struct Keys<'a, KB: 'static + Bounds, VB: 'static + Bounds>(
std::collections::hash_map::Keys<'a, TypedKey<KB>, TypedMapValue<VB>>,
);
impl<'a, KB: 'static + Bounds, VB: 'static + Bounds> Iterator for Keys<'a, KB, VB> {
type Item = &'a dyn Any;
fn next(&mut self) -> Option<Self::Item> {
let key = self.0.next()?;
Some(key.as_any())
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<KB, VB> ExactSizeIterator for Keys<'_, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
}
impl<KB, VB> FusedIterator for Keys<'_, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
}
#[derive(Clone)]
pub struct Values<'a, KB: 'static + Bounds, VB: 'static + Bounds>(
std::collections::hash_map::Values<'a, TypedKey<KB>, TypedMapValue<VB>>,
);
impl<'a, KB: 'static + Bounds, VB: 'static + Bounds> Iterator for Values<'a, KB, VB> {
type Item = &'a dyn Any;
fn next(&mut self) -> Option<Self::Item> {
let value = self.0.next()?;
Some(value.as_any())
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<KB, VB> ExactSizeIterator for Values<'_, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
}
impl<KB, VB> FusedIterator for Values<'_, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
}
pub struct ValuesMut<'a, KB: 'static + Bounds, VB: 'static + Bounds>(
std::collections::hash_map::ValuesMut<'a, TypedKey<KB>, TypedMapValue<VB>>,
);
impl<'a, KB, VB> Iterator for ValuesMut<'a, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
type Item = &'a mut dyn Any;
fn next(&mut self) -> Option<Self::Item> {
let value = self.0.next()?;
Some(value.as_mut_any())
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<KB, VB> ExactSizeIterator for ValuesMut<'_, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
}
impl<KB, VB> FusedIterator for ValuesMut<'_, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
}
pub struct TypedKeyValue<Marker, KB: 'static + Bounds, VB: 'static + Bounds> {
pub(crate) key: TypedKey<KB>,
pub(crate) value: TypedMapValue<VB>,
pub(crate) _marker: PhantomData<Marker>,
}
impl<Marker, KB, VB> TypedKeyValue<Marker, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
pub fn new<K>(key: K, value: K::Value) -> Self
where
KB: HasBounds<K>,
VB: HasBounds<K::Value>,
K: 'static + TypedMapKey<Marker>,
{
TypedKeyValue {
key: TypedKey::from_key(key),
value: TypedMapValue::from_value(value),
_marker: PhantomData,
}
}
pub fn downcast_key_ref<K: 'static + TypedMapKey<Marker>>(&self) -> Option<&K>
where
KB: HasBounds<K>,
{
self.key.downcast_ref()
}
pub fn downcast_key<K: 'static + TypedMapKey<Marker>>(self) -> Result<K, Self>
where
KB: HasBounds<K>,
{
let Self {
key,
value,
_marker,
} = self;
key.downcast().map_err(|key| Self {
key,
value,
_marker,
})
}
pub fn downcast_value_ref<V: 'static>(&self) -> Option<&V>
where
VB: HasBounds<V>,
{
self.value.downcast_ref()
}
pub fn downcast_value<V: 'static>(self) -> Result<V, Self>
where
VB: HasBounds<V>,
{
let Self {
key,
value,
_marker,
} = self;
value.downcast().map_err(|value| Self {
key,
value,
_marker,
})
}
pub fn downcast_pair_ref<K>(&self) -> Option<(&K, &K::Value)>
where
K: 'static + TypedMapKey<Marker>,
KB: HasBounds<K>,
VB: HasBounds<K::Value>,
{
let key = self.downcast_key_ref()?;
let value = self.downcast_value_ref()?;
Some((key, value))
}
pub fn downcast_pair<K>(self) -> Result<(K, K::Value), Self>
where
K: 'static + TypedMapKey<Marker>,
KB: HasBounds<K>,
VB: HasBounds<K::Value>,
{
let Self {
key,
value,
_marker,
} = self;
match key.downcast() {
Ok(key) => match value.downcast() {
Ok(value) => Ok((key, value)),
Err(dyn_value) => Err(Self {
key: TypedKey::from_key(key),
value: dyn_value,
_marker,
}),
},
Err(dyn_key) => Err(Self {
key: dyn_key,
value,
_marker,
}),
}
}
pub fn key_container_ref(&self) -> &KB::Container {
self.key.as_container()
}
pub fn key_container_mut(&mut self) -> &mut KB::Container {
self.key.as_mut_container()
}
pub fn value_container_ref(&self) -> &VB::Container {
self.value.as_container()
}
pub fn value_container_mut(&mut self) -> &mut VB::Container {
self.value.as_mut_container()
}
pub fn into_key_container(self) -> Box<KB::Container> {
self.key.into_box_container()
}
pub fn into_value_container(self) -> Box<VB::Container> {
self.value.into_box_container()
}
pub fn into_container_pair(self) -> (Box<KB::Container>, Box<VB::Container>) {
(
self.key.into_box_container(),
self.value.into_box_container(),
)
}
}
impl<M, KB: 'static + Bounds, VB: 'static + Bounds> Debug for TypedKeyValue<M, KB, VB> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("TypedKeyValue")
}
}
pub struct TypedKeyValueRef<'a, Marker, KB: 'static + Bounds, VB: 'static + Bounds> {
key: &'a TypedKey<KB>,
value: &'a TypedMapValue<VB>,
_marker: PhantomData<Marker>,
}
impl<'a, Marker, KB: 'static + Bounds, VB: 'static + Bounds> TypedKeyValueRef<'a, Marker, KB, VB> {
pub fn downcast_key_ref<K: 'static + TypedMapKey<Marker>>(&self) -> Option<&'a K>
where
KB: HasBounds<K>,
{
self.key.downcast_ref()
}
pub fn downcast_value_ref<V: 'static>(&self) -> Option<&'a V>
where
VB: HasBounds<V>,
{
self.value.downcast_ref()
}
pub fn downcast_pair_ref<K>(&self) -> Option<(&'a K, &'a K::Value)>
where
K: 'static + TypedMapKey<Marker>,
KB: HasBounds<K>,
VB: HasBounds<K::Value>,
{
self.downcast_key_ref()
.and_then(move |key| self.downcast_value_ref().map(move |value| (key, value)))
}
pub fn key_container_ref(&self) -> &KB::Container {
self.key.as_container()
}
pub fn value_container_ref(&self) -> &VB::Container {
self.value.as_container()
}
}
impl<M, KB: 'static + Bounds, VB: 'static + Bounds> Debug for TypedKeyValueRef<'_, M, KB, VB> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("TypedKeyValueRef")
}
}
#[cfg(feature = "clone")]
impl<M, KB: Bounds, VB: Bounds> TypedKeyValueRef<'_, M, KB, VB>
where
KB::KeyContainer: crate::clone::CloneAny,
VB::Container: crate::clone::CloneAny,
{
pub fn to_owned(&self) -> TypedKeyValue<M, KB, VB> {
let key = crate::clone::clone_box(&*self.key.0);
let value = crate::clone::clone_box(self.value.as_container());
TypedKeyValue {
key: TypedKey(key),
value: TypedMapValue(value),
_marker: self._marker,
}
}
}
pub struct TypedKeyValueMutRef<'a, Marker, KB: 'static + Bounds, VB: 'static + Bounds> {
key: &'a TypedKey<KB>,
value: &'a mut TypedMapValue<VB>,
_marker: PhantomData<Marker>,
}
impl<'a, Marker, KB, VB> TypedKeyValueMutRef<'a, Marker, KB, VB>
where
KB: 'static + Bounds,
VB: 'static + Bounds,
{
pub fn downcast_key_ref<K>(&self) -> Option<&'a K>
where
KB: HasBounds<K>,
K: 'static + TypedMapKey<Marker>,
{
self.key.downcast_ref()
}
pub fn downcast_value_mut<'b, V>(&'b mut self) -> Option<&'b mut V>
where
'a: 'b,
V: 'static,
VB: HasBounds<V>,
{
self.value.downcast_mut()
}
pub fn downcast_value<V>(self) -> Result<&'a mut V, Self>
where
V: 'static,
VB: HasBounds<V>,
{
if self.value.is::<V>() {
Ok(self.value.downcast_mut().expect("Unreachable!"))
} else {
Err(self)
}
}
pub fn downcast_pair_mut<'b, K>(&'b mut self) -> Option<(&'b K, &'b mut K::Value)>
where
'a: 'b,
K: 'static + TypedMapKey<Marker>,
KB: HasBounds<K>,
VB: HasBounds<K::Value>,
{
self.downcast_key_ref()
.and_then(move |key| self.downcast_value_mut().map(move |value| (key, value)))
}
pub fn downcast_pair<K>(self) -> Result<(&'a K, &'a mut K::Value), Self>
where
K: 'static + TypedMapKey<Marker>,
KB: HasBounds<K>,
VB: HasBounds<K::Value>,
{
let key = self.downcast_key_ref();
let key = match key {
Some(key) => key,
None => return Err(self),
};
match self.downcast_value() {
Ok(value) => Ok((key, value)),
Err(err) => Err(err),
}
}
pub fn key_container_ref(&self) -> &KB::Container {
self.key.as_container()
}
pub fn value_container_ref(&self) -> &VB::Container {
self.value.as_container()
}
pub fn value_container_mut(&mut self) -> &mut VB::Container {
self.value.as_mut_container()
}
}
#[cfg(feature = "clone")]
impl<M, KB: Bounds, VB: Bounds> TypedKeyValueMutRef<'_, M, KB, VB>
where
KB::KeyContainer: crate::clone::CloneAny,
VB::Container: crate::clone::CloneAny,
{
pub fn to_owned(&self) -> TypedKeyValue<M, KB, VB> {
let key = crate::clone::clone_box(&*self.key.0);
let value = crate::clone::clone_box(self.value.as_container());
TypedKeyValue {
key: TypedKey(key),
value: TypedMapValue(value),
_marker: self._marker,
}
}
}
impl<M, KB: 'static + Bounds, VB: 'static + Bounds> Debug for TypedKeyValueMutRef<'_, M, KB, VB> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("TypedMutRef")
}
}
impl<M, KB: Bounds, VB: Bounds> FromIterator<TypedKeyValue<M, KB, VB>> for TypedMap<M, KB, VB> {
fn from_iter<T: IntoIterator<Item = TypedKeyValue<M, KB, VB>>>(iter: T) -> Self {
let state = iter.into_iter().map(|i| (i.key, i.value)).collect();
TypedMap {
state,
_phantom: PhantomData,
}
}
}
#[cfg(test)]
mod tests {
use std::hash::Hash;
use crate::TypedMap;
use crate::TypedMapKey;
struct M;
impl TypedMapKey<M> for String {
type Value = String;
}
#[test]
fn test_basic_use() {
struct OtherState;
let mut state = TypedMap::new();
let mut other_state = TypedMap::<OtherState>::new();
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
struct AThing;
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
struct BThing(usize);
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
struct CThing(usize);
impl TypedMapKey for AThing {
type Value = String;
}
impl TypedMapKey for BThing {
type Value = usize;
}
impl TypedMapKey<OtherState> for CThing {
type Value = usize;
}
state.insert(AThing, "Example".to_owned());
state.insert(BThing(32), 33);
state.insert(BThing(33), 34);
other_state.insert(CThing(0), 33);
assert_eq!(state.get(&AThing), Some(&"Example".to_owned()));
assert_eq!(state.get(&BThing(0)), None);
assert_eq!(state.get(&BThing(32)), Some(&33));
assert_eq!(state.get(&BThing(33)), Some(&34));
assert_eq!(other_state.get(&CThing(0)), Some(&33));
*state.entry(BThing(3)).or_default() += 1;
assert_eq!(*state.get(&BThing(3)).unwrap(), 1usize);
*state.entry(BThing(4)).or_insert(3usize) += 1;
*state.entry(BThing(4)).or_insert(3usize) += 1;
assert_eq!(*state.get(&BThing(4)).unwrap(), 5usize);
if let crate::entry::Entry::Occupied(occupied) = state.entry(BThing(3)) {
let (k, v) = occupied.remove_entry();
assert_eq!(k, BThing(3));
assert_eq!(v, 1usize);
} else {
panic!()
}
let mut b_entries: Vec<_> = state
.iter()
.flat_map(|r| r.downcast_pair_ref::<BThing>())
.collect();
b_entries.sort_by_key(|kv| (kv.0).0);
let b4 = BThing(4);
let b32 = BThing(32);
let b33 = BThing(33);
assert_eq!(
b_entries,
vec![(&b4, &5usize), (&b32, &33usize), (&b33, &34usize)]
);
state.iter_mut().for_each(|mut r| {
if let Some((_, value)) = r.downcast_pair_mut::<BThing>() {
*value += 1;
}
});
let b_things = state
.iter_mut()
.flat_map(|r| r.downcast_pair::<BThing>())
.count();
assert_eq!(b_things, 3);
}
#[test]
fn test_always_equal_types() {
let mut state = TypedMap::new();
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
struct AThing;
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
struct BThing;
trait Foo {}
impl Foo for AThing {}
impl Foo for BThing {}
impl Hash for Box<dyn Foo> {
fn hash<H>(&self, hasher: &mut H)
where
H: std::hash::Hasher,
{
0.hash(hasher);
}
}
impl PartialEq for Box<dyn Foo> {
fn eq(&self, _rhs: &Self) -> bool {
true
}
}
impl Eq for Box<dyn Foo> {}
impl TypedMapKey for AThing {
type Value = String;
}
impl TypedMapKey for BThing {
type Value = usize;
}
impl TypedMapKey for Box<dyn Foo> {
type Value = String;
}
let key_a = Box::new(AThing);
let key_b = Box::new(BThing);
state.insert(key_a.clone() as Box<dyn Foo>, "test1".to_owned());
let old_key = state
.insert(key_b.clone() as Box<dyn Foo>, "test2".to_owned())
.unwrap();
assert_eq!(old_key, "test1".to_owned());
let key_a = &(key_a as Box<dyn Foo>);
let key_b = &(key_b as Box<dyn Foo>);
assert_eq!(state.get(key_a).unwrap(), &"test2".to_owned());
assert_eq!(state.get(key_b).unwrap(), &"test2".to_owned());
assert_eq!(state.remove(key_a).unwrap(), "test2".to_owned());
assert!(state.is_empty());
assert_eq!(state.len(), 0);
}
#[test]
fn test_from_iterator() {
let mut state: TypedMap<M> = TypedMap::new();
state.insert("key".to_owned(), "value".to_owned());
let new_map: TypedMap<M> = state.into_iter().collect();
assert_eq!(new_map.get(&"key".to_owned()), Some(&"value".to_owned()));
}
}