use std::{
marker::PhantomData,
sync::{Arc, Weak},
};
use rich_phantoms::PhantomInvariantAlwaysSendSync;
use slab::Slab;
#[must_use]
#[derive(Clone, Debug)]
pub struct ObjectRef<T> {
index: usize,
rc: Arc<PhantomInvariantAlwaysSendSync<T>>,
}
struct Object<T> {
rc: Weak<PhantomInvariantAlwaysSendSync<T>>,
data: T,
}
impl<T> Object<T> {
fn verify(&self, obj_ref: &ObjectRef<T>) {
assert_eq!(Arc::as_ptr(&obj_ref.rc), Weak::as_ptr(&self.rc));
}
}
pub struct ObjectStore<T> {
slab: Slab<Object<T>>,
}
impl<T> Default for ObjectStore<T> {
fn default() -> Self {
Self { slab: Slab::new() }
}
}
impl<T> ObjectStore<T> {
pub fn get(&self, obj_ref: &ObjectRef<T>) -> &T {
let obj = &self.slab[obj_ref.index];
obj.verify(obj_ref);
&obj.data
}
pub fn get_mut(&mut self, obj_ref: &ObjectRef<T>) -> &mut T {
let obj = &mut self.slab[obj_ref.index];
obj.verify(obj_ref);
&mut obj.data
}
pub fn clean(&mut self) {
self.slab.retain(|_i, obj| obj.rc.strong_count() > 0)
}
pub fn insert(&mut self, data: T) -> ObjectRef<T> {
let rc = Arc::new(PhantomData);
let rc_for_return = rc.clone();
let obj = Object {
rc: Arc::downgrade(&rc),
data,
};
let index = self.slab.insert(obj);
ObjectRef {
index,
rc: rc_for_return,
}
}
pub fn remove(&mut self, obj_ref: ObjectRef<T>) -> Option<T> {
let index = obj_ref.index;
self.slab[index].verify(&obj_ref);
if Arc::try_unwrap(obj_ref.rc).is_ok() {
Some(self.slab.remove(index).data)
} else {
None
}
}
}