use crate::{Handle, HandleMap};
use core::marker::PhantomData;
#[derive(Clone, Debug)]
pub struct TypedHandleMap<T>(HandleMap<T>);
impl<T> TypedHandleMap<T> {
#[inline]
pub fn new() -> Self {
Self(HandleMap::new())
}
#[inline]
pub fn from_untyped(h: HandleMap<T>) -> Self {
Self(h)
}
#[inline]
pub fn into_untyped(self) -> HandleMap<T> {
self.0
}
#[inline]
pub fn with_capacity(c: usize) -> Self {
Self::from_untyped(HandleMap::with_capacity(c))
}
#[inline]
pub fn capacity(&self) -> usize {
self.0.capacity()
}
#[inline]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline]
pub fn as_untyped_map(&self) -> &HandleMap<T> {
&self.0
}
#[inline]
pub fn as_mut_untyped_map(&mut self) -> &mut HandleMap<T> {
&mut self.0
}
#[inline]
pub fn insert(&mut self, value: T) -> TypedHandle<T> {
TypedHandle::from_handle(self.0.insert(value))
}
#[inline]
pub fn remove(&mut self, handle: TypedHandle<T>) -> Option<T> {
self.0.remove(handle.h)
}
#[inline]
pub fn clear(&mut self) {
self.0.clear();
}
#[inline]
pub fn get(&self, handle: TypedHandle<T>) -> Option<&T> {
self.0.get(handle.h)
}
#[inline]
pub fn get_mut(&mut self, handle: TypedHandle<T>) -> Option<&mut T> {
self.0.get_mut(handle.h)
}
#[inline]
pub fn contains(&self, h: TypedHandle<T>) -> bool {
self.0.contains_key(h.h)
}
#[inline]
pub fn contains_key(&self, h: TypedHandle<T>) -> bool {
self.0.contains_key(h.h)
}
#[inline]
pub fn find_handle(&self, item: &T) -> Option<TypedHandle<T>>
where
T: PartialEq,
{
self.0.find_handle(item).map(TypedHandle::from_handle)
}
pub fn reserve(&mut self, sz: usize) {
self.0.reserve(sz)
}
#[inline]
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a T> + 'a {
self.0.iter()
}
#[inline]
pub fn iter_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut T> + 'a {
self.0.iter_mut()
}
#[inline]
pub fn iter_with_handles<'a>(&'a self) -> impl Iterator<Item = (TypedHandle<T>, &'a T)> + 'a {
self.0
.iter_with_handles()
.map(|(h, v)| (TypedHandle::from_handle(h), v))
}
#[inline]
pub fn iter_mut_with_handles<'a>(
&'a mut self,
) -> impl Iterator<Item = (TypedHandle<T>, &'a mut T)> + 'a {
self.0
.iter_mut_with_handles()
.map(|(h, v)| (TypedHandle::from_handle(h), v))
}
#[inline]
pub fn handle_for_index(&self, index: usize) -> Option<TypedHandle<T>> {
self.0.handle_for_index(index).map(TypedHandle::from_handle)
}
}
#[repr(transparent)]
pub struct TypedHandle<T> {
h: Handle,
_marker: PhantomData<fn() -> T>,
}
impl<T> TypedHandle<T> {
pub const EMPTY: Self = Self::from_handle(Handle::EMPTY);
#[inline]
pub const fn from_handle(h: Handle) -> Self {
Self {
h,
_marker: Self::BOO,
}
}
const BOO: PhantomData<fn() -> T> = PhantomData;
#[inline]
pub const fn handle(self) -> Handle {
self.h
}
#[inline]
pub const fn from_raw_parts(index: usize, generation: u16, meta: u16) -> Self {
Self::from_handle(Handle::from_raw_parts(index, generation, meta))
}
#[inline]
pub const fn from_raw(value: u64) -> Self {
Self::from_handle(Handle::from_raw(value))
}
#[inline]
pub const fn into_raw(self) -> u64 {
self.h.0
}
#[inline]
pub const fn index(self) -> usize {
self.h.index()
}
#[inline]
pub const fn generation(self) -> u16 {
self.h.generation()
}
#[inline]
pub const fn meta(self) -> u16 {
self.h.meta()
}
#[inline]
pub const fn map_id(self) -> u16 {
self.h.map_id()
}
}
impl<T> core::ops::Index<TypedHandle<T>> for TypedHandleMap<T> {
type Output = T;
fn index(&self, h: TypedHandle<T>) -> &T {
self.get(h).expect("Invalid handle used in index")
}
}
impl<T> core::ops::IndexMut<TypedHandle<T>> for TypedHandleMap<T> {
fn index_mut(&mut self, h: TypedHandle<T>) -> &mut T {
self.get_mut(h).expect("Invalid handle used in index_mut")
}
}
impl<T> Default for TypedHandleMap<T> {
fn default() -> Self { Self::new() }
}
impl<T> Clone for TypedHandle<T> {
#[inline]
fn clone(&self) -> Self {
Self {
h: self.h,
_marker: PhantomData,
}
}
}
impl<T> Copy for TypedHandle<T> {}
impl<T> Eq for TypedHandle<T> {}
impl<T> PartialEq for TypedHandle<T> {
#[inline]
fn eq(&self, o: &Self) -> bool {
self.h.0 == o.h.0
}
#[inline]
#[allow(clippy::partialeq_ne_impl)] fn ne(&self, o: &Self) -> bool {
self.h.0 != o.h.0
}
}
impl<T> PartialOrd for TypedHandle<T> {
#[inline]
fn partial_cmp(&self, o: &Self) -> Option<core::cmp::Ordering> {
self.h.0.partial_cmp(&o.h.0)
}
#[inline]
fn lt(&self, o: &Self) -> bool {
self.h.0 < o.h.0
}
#[inline]
fn le(&self, o: &Self) -> bool {
self.h.0 <= o.h.0
}
#[inline]
fn ge(&self, o: &Self) -> bool {
self.h.0 >= o.h.0
}
#[inline]
fn gt(&self, o: &Self) -> bool {
self.h.0 > o.h.0
}
}
impl<T> IntoIterator for TypedHandleMap<T> {
type IntoIter = crate::IntoIter<T>;
type Item = T;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<T> Ord for TypedHandle<T> {
#[inline]
fn cmp(&self, o: &Self) -> core::cmp::Ordering {
self.h.0.cmp(&o.h.0)
}
}
impl<T> Default for TypedHandle<T> {
#[inline]
fn default() -> Self {
Self {
h: Handle::EMPTY,
_marker: PhantomData,
}
}
}
impl<T> core::hash::Hash for TypedHandle<T> {
#[inline]
fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
core::hash::Hash::hash(&self.h, h)
}
}
impl<T> core::fmt::Debug for TypedHandle<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("TypedHandle").field(&self.h).finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_handle_parts() {
let h = TypedHandle::<()>::from_raw_parts(0, 0, 0);
assert_eq!(h.index(), 0);
assert_eq!(h.generation(), 0);
assert_eq!(h.meta(), 0);
assert_eq!(h.meta(), h.map_id());
let h = TypedHandle::<()>::from_raw_parts(!0, 0, 0);
assert_eq!(h.index(), (!0u32) as usize);
assert_eq!(h.generation(), 0);
assert_eq!(h.meta(), 0);
assert_eq!(h.meta(), h.map_id());
assert_eq!(TypedHandle::<()>::from_raw(h.into_raw()), h);
let h = TypedHandle::<()>::from_raw_parts(0, !0, 0);
assert_eq!(h.index(), 0);
assert_eq!(h.generation(), !0);
assert_eq!(h.meta(), 0);
assert_eq!(h.meta(), h.map_id());
let h = TypedHandle::<()>::from_raw_parts(0, 0, !0);
assert_eq!(h.index(), 0);
assert_eq!(h.generation(), 0);
assert_eq!(h.meta(), !0);
assert_eq!(h.meta(), h.map_id());
let h = TypedHandle::<()>::from_raw_parts(!0, !0, !0);
assert_eq!(h.index(), (!0u32) as usize);
assert_eq!(h.generation(), !0);
assert_eq!(h.meta(), !0);
assert_eq!(h.meta(), h.map_id());
}
use crate::tests::Foobar;
#[test]
fn test_correct_value_single() {
let mut map = TypedHandleMap::new();
let handle = map.insert(Foobar(1234));
assert_eq!(map.get(handle).unwrap(), &Foobar(1234));
map.remove(handle).unwrap();
assert_eq!(map.get(handle), None);
let handle = map.as_mut_untyped_map().insert(Foobar(1234));
assert_eq!(
map.get(TypedHandle::from_handle(handle)).unwrap(),
&Foobar(1234)
);
}
#[test]
fn test_indexing() {
let mut map = TypedHandleMap::new();
let handle = map.insert(Foobar(5454));
assert_eq!(map[handle].0, 5454);
map[handle] = Foobar(6767);
assert_eq!(map[handle].0, 6767);
}
#[test]
fn test_correct_value_multiple() {
let mut map = TypedHandleMap::new();
let handle1 = map.insert(Foobar(1234));
let handle2 = map.insert(Foobar(4321));
assert_eq!(map.get(handle1).unwrap(), &Foobar(1234));
assert_eq!(map.get(handle2).unwrap(), &Foobar(4321));
map.remove(handle1).unwrap();
assert_eq!(map.get(handle1), None);
assert_eq!(map.get(handle2).unwrap(), &Foobar(4321));
}
#[test]
fn test_wrong_map() {
let mut map1 = TypedHandleMap::new();
let mut map2 = TypedHandleMap::new();
let handle1 = map1.insert(Foobar(1234));
let handle2 = map2.insert(Foobar(1234));
assert_eq!(map1.get(handle1).unwrap(), &Foobar(1234));
assert_eq!(map2.get_mut(handle2).unwrap(), &mut Foobar(1234));
assert_eq!(map1.get(handle2), None);
assert_eq!(map2.get_mut(handle1), None);
}
#[test]
fn test_bad_index() {
let map: TypedHandleMap<Foobar> = TypedHandleMap::new();
assert_eq!(
map.get(TypedHandle::<Foobar>::from_raw_parts(
100,
2,
map.as_untyped_map().map_id()
)),
None
);
}
#[test]
fn test_reserve() {
let mut map = TypedHandleMap::<u32>::with_capacity(10);
let cap0 = map.capacity();
map.reserve(cap0 + 10);
assert!(map.capacity() >= cap0 + 10);
}
#[test]
fn test_clear() {
let mut map = HandleMap::new();
map.insert(5u32);
assert!(map.len() == 1);
map.clear();
assert!(map.is_empty());
}
#[test]
fn test_iters() {
use alloc::collections::BTreeMap;
let (map, handles) = crate::tests::mixed_handlemap();
let mut map = TypedHandleMap::from_untyped(map);
let handles = handles
.into_iter()
.map(|(h, v)| (TypedHandle::<Foobar>::from_handle(h), v))
.collect::<alloc::vec::Vec<_>>();
assert_eq!(map.len(), handles.len());
let handle_to_foo: BTreeMap<TypedHandle<Foobar>, usize> = handles.iter().copied().collect();
let foo_to_handle: BTreeMap<usize, TypedHandle<Foobar>> =
handles.iter().copied().map(|t| (t.1, t.0)).collect();
assert_eq!(handle_to_foo.len(), handles.len());
assert_eq!(foo_to_handle.len(), handles.len());
let mut count = 0;
for i in map.iter() {
count += 1;
assert!(foo_to_handle.contains_key(&i.0));
}
assert_eq!(count, handles.len());
let mut count = 0;
for i in map.iter_mut() {
count += 1;
assert!(foo_to_handle.contains_key(&i.0));
}
assert_eq!(count, handles.len());
let mut count = 0;
for i in map.clone() {
count += 1;
assert!(foo_to_handle.contains_key(&i.0));
}
assert_eq!(count, handles.len());
let mut count = 0;
for (h, i) in map.iter_with_handles() {
count += 1;
assert!(foo_to_handle.contains_key(&i.0));
assert_eq!(handle_to_foo[&h], i.0);
}
assert_eq!(count, handles.len());
let mut count = 0;
for (h, i) in map.iter_mut_with_handles() {
count += 1;
assert!(foo_to_handle.contains_key(&i.0));
assert_eq!(handle_to_foo[&h], i.0);
}
assert_eq!(count, handles.len());
}
#[test]
fn test_find() {
let mut m = TypedHandleMap::new();
let mut v = alloc::vec![];
for i in 0..10usize {
v.push(m.insert(i));
}
for (i, h) in v.iter().enumerate() {
assert_eq!(m.find_handle(&i), Some(*h));
assert!(m.contains_key(*h));
}
m.clear();
assert!(m.is_empty());
for (i, h) in v.iter().enumerate() {
assert_eq!(m.find_handle(&i), None);
assert!(!m.contains_key(*h));
}
}
#[test]
fn test_handle_traits() {
fn verify<T>()
where
T: Clone
+ Copy
+ PartialEq
+ PartialOrd
+ Eq
+ Ord
+ core::hash::Hash
+ Default
+ Send
+ Sync,
{
}
verify::<TypedHandle<u32>>();
verify::<TypedHandle<*const u32>>();
verify::<TypedHandle<core::cell::UnsafeCell<u32>>>();
verify::<TypedHandle<alloc::vec::Vec<u32>>>();
}
#[allow(dead_code, unused_assignments, unused_variables)]
fn check_handle_variance<'a, 'b: 'a>(mut x: TypedHandle<&'a u32>, y: TypedHandle<&'b u32>) {
x = y;
}
#[test]
#[allow(clippy::clone_on_copy, clippy::cognitive_complexity)]
fn test_trait_impls() {
use core::cmp::Ordering;
use core::hash::Hash;
type TH = TypedHandle<()>;
assert!(TH::from_raw(3) == TH::from_raw(3));
assert!(TH::from_raw(3) != TH::from_raw(4));
assert!(!(TH::from_raw(3) != TH::from_raw(3)));
assert!(!(TH::from_raw(3) == TH::from_raw(4)));
assert!(TH::from_raw(3) < TH::from_raw(4));
assert!(TH::from_raw(4) > TH::from_raw(3));
assert!(!(TH::from_raw(4) < TH::from_raw(4)));
assert!(!(TH::from_raw(4) < TH::from_raw(3)));
assert!(!(TH::from_raw(4) > TH::from_raw(4)));
assert!(!(TH::from_raw(3) > TH::from_raw(4)));
assert!(TH::from_raw(3) <= TH::from_raw(4));
assert!(TH::from_raw(3) <= TH::from_raw(3));
assert!(TH::from_raw(4) >= TH::from_raw(3));
assert!(TH::from_raw(4) >= TH::from_raw(4));
assert!(!(TH::from_raw(5) <= TH::from_raw(4)));
assert!(!(TH::from_raw(4) >= TH::from_raw(5)));
assert_eq!(
TH::from_raw(4).partial_cmp(&TH::from_raw(4)),
Some(Ordering::Equal)
);
assert_eq!(
TH::from_raw(5).partial_cmp(&TH::from_raw(4)),
Some(Ordering::Greater)
);
assert_eq!(
TH::from_raw(5).partial_cmp(&TH::from_raw(6)),
Some(Ordering::Less)
);
assert_eq!(TH::from_raw(4).cmp(&TH::from_raw(4)), Ordering::Equal);
assert_eq!(TH::from_raw(5).cmp(&TH::from_raw(4)), Ordering::Greater);
assert_eq!(TH::from_raw(5).cmp(&TH::from_raw(6)), Ordering::Less);
assert_eq!(TH::from_raw(5).clone(), TH::from_raw(5));
let mut h = H_DEFAULT;
TH::from_raw(10).hash(&mut h);
let mut h2 = H_DEFAULT;
Handle::from_raw(10).hash(&mut h2);
assert_eq!(h.0, h2.0);
assert_eq!(
&alloc::format!("{:?}", TH::from_raw_parts(10, 20, 30)),
"TypedHandle(Handle { meta: 30, generation: 20, index: 10 })",
);
}
struct HashTester(u64);
const H_DEFAULT: HashTester = HashTester(0xcbf2_9ce4_8422_2325);
impl core::hash::Hasher for HashTester {
fn write(&mut self, bytes: &[u8]) {
for b in bytes {
self.0 = self.0.wrapping_mul(0x100_0000_01b3);
self.0 ^= u64::from(*b);
}
}
fn finish(&self) -> u64 {
self.0
}
}
}