use core::cmp::Ordering;
use core::fmt::{Debug, Formatter, Result as FmtResult};
use core::marker::PhantomData;
use core::sync::atomic::AtomicUsize;
use crate::key::Key;
pub struct Handle<T> {
id: usize,
index: usize,
count: usize,
marker: PhantomData<T>,
}
unsafe impl<T> Send for Handle<T> {}
unsafe impl<T> Sync for Handle<T> {}
impl<T> Eq for Handle<T> {}
impl<T> PartialEq<Self> for Handle<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.index == other.index && self.count == other.count
}
}
impl<T> Ord for Handle<T> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
match self.count.cmp(&other.count) {
Ordering::Equal => (),
o => return o,
}
match self.index.cmp(&other.index) {
Ordering::Equal => (),
o => return o,
}
Ordering::Equal
}
}
impl<T> PartialOrd<Self> for Handle<T> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T> Copy for Handle<T> {}
impl<T> Clone for Handle<T> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T> Debug for Handle<T> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.debug_struct("Handle")
.field("count", &self.count)
.field("index", &self.index)
.finish()
}
}
impl<T> Key<T> for Handle<T> {
type Context = Context;
type VacantData = usize;
type OccupiedData = usize;
#[inline]
fn index(&self, cx: &Self::Context) -> usize {
let _cx = cx;
self.index
}
#[inline]
fn verify(&self, cx: &Self::Context, data: &Self::OccupiedData) -> bool {
self.id == cx.id && self.count == *data
}
#[inline]
fn new_vacant(cx: &Self::Context, index: usize, data: Option<&Self::VacantData>) -> Self {
Self {
id: cx.id,
index,
count: data.cloned().unwrap_or_default(),
marker: PhantomData,
}
}
#[inline]
fn new_occupied(cx: &Self::Context, index: usize, data: &Self::OccupiedData) -> Self {
Self {
id: cx.id,
index,
count: *data,
marker: PhantomData,
}
}
#[inline]
fn convert_into_vacant(cx: &Self::Context, data: Self::OccupiedData) -> Self::VacantData {
let _cx = cx;
data.overflowing_add(1).0
}
#[inline]
fn convert_into_occupied(cx: &Self::Context, data: Self::VacantData) -> Self::OccupiedData {
let _cx = cx;
data
}
#[inline]
fn into_occupied_data(self) -> Self::OccupiedData {
self.count
}
}
#[derive(Debug, Clone)]
pub struct Context {
id: usize,
}
impl Default for Context {
fn default() -> Self {
Self {
id: NEXT_ID.fetch_add(1, core::sync::atomic::Ordering::Relaxed),
}
}
}
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
#[cfg(test)]
mod tests {
use crate::StrongSlab;
#[test]
fn strong_slab() {
let mut slab = StrongSlab::new();
let handle0 = slab.insert("hello");
assert_eq!(handle0.index, 0);
assert_eq!(handle0.count, 0);
slab.remove(handle0);
let handle1 = slab.insert("world");
assert!(slab.get(handle0).is_none());
assert_eq!(handle1.index, 0);
assert_eq!(handle1.count, 1);
}
}