use std::marker::PhantomData;
use crate::{
base::marker::ThreadBound,
depot::map::{
self, resident,
resident::{Key, Table},
},
};
type Brand<'id> = PhantomData<(fn(&'id mut ()) -> &'id mut (), ThreadBound)>;
pub struct Scope<'a, 'id, T, H, const MAX: u32> {
table: &'a mut Table<T, H, MAX>,
brand: Brand<'id>,
}
pub struct Lease<'id, const MAX: u32> {
key: Key<MAX>,
brand: Brand<'id>,
}
pub struct Fresh<'id, const MAX: u32> {
key: Key<MAX>,
brand: Brand<'id>,
}
pub struct Retirement<'a, 'id, T, H, const MAX: u32> {
table: &'a mut Table<T, H, MAX>,
brand: Brand<'id>,
}
pub struct Occupied<'a, 'id, T, H, const MAX: u32> {
entry: resident::Occupied<'a, T, H, MAX>,
brand: Brand<'id>,
}
pub struct Vacant<'a, 'id, T, H, const MAX: u32> {
entry: resident::Vacant<'a, T, H, MAX>,
brand: Brand<'id>,
}
impl<'a, 'id, T, H: map::Hasher<resident::Id>, const MAX: u32> Scope<'a, 'id, T, H, MAX> {
pub(super) fn new(table: &'a mut Table<T, H, MAX>) -> Self {
Self {
brand: PhantomData,
table,
}
}
pub fn entry(
&mut self,
id: resident::Id,
) -> map::Entry<Occupied<'_, 'id, T, H, MAX>, Option<Vacant<'_, 'id, T, H, MAX>>> {
match self.table.entry(id) {
map::Entry::Occupied(mut entry) => {
entry.bucket = None;
map::Entry::Occupied(Occupied {
entry,
brand: self.brand,
})
}
map::Entry::Vacant(entry) => map::Entry::Vacant(entry.map(|entry| Vacant {
entry,
brand: self.brand,
})),
}
}
pub fn exact(
&mut self,
key: Key<MAX>,
id: resident::Id,
) -> Result<Occupied<'_, 'id, T, H, MAX>, &Table<T, H, MAX>> {
match self.table.exact(key, id) {
Ok(entry) => Ok(Occupied {
entry,
brand: self.brand,
}),
Err(table) => Err(table),
}
}
pub fn get_mut(&mut self, lease: &Lease<'id, MAX>) -> &mut T {
unsafe {
self.table
.records
.get_unchecked_mut(lease.key.index() as usize)
.value
.assume_init_mut()
}
}
pub fn retire(self) -> Retirement<'a, 'id, T, H, MAX> {
Retirement {
table: self.table,
brand: self.brand,
}
}
}
impl<'a, 'id, T, H: map::Hasher<resident::Id>, const MAX: u32> Vacant<'a, 'id, T, H, MAX> {
pub fn insert(self, value: T) -> Occupied<'a, 'id, T, H, MAX> {
Occupied {
entry: self.entry.insert(value),
brand: self.brand,
}
}
}
impl<T, H: map::Hasher<resident::Id>, const MAX: u32> Occupied<'_, '_, T, H, MAX> {
pub fn id(&self) -> resident::Id {
self.entry.id()
}
pub fn get_mut(&mut self) -> &mut T {
self.entry.get_mut()
}
pub fn release(self) -> Option<T> {
self.entry.bucket.is_some().then(|| self.entry.remove())
}
}
impl<'id, T, H: map::Hasher<resident::Id>, const MAX: u32> Occupied<'_, 'id, T, H, MAX> {
pub fn publish(self) -> (Lease<'id, MAX>, Option<Fresh<'id, MAX>>) {
let key = self.entry.key();
let lease = Lease {
key,
brand: self.brand,
};
let fresh = self.entry.bucket.map(|_| Fresh {
key,
brand: self.brand,
});
(lease, fresh)
}
}
impl<const MAX: u32> Lease<'_, MAX> {
pub const fn key(&self) -> Key<MAX> {
self.key
}
}
impl<'id, T, H: map::Hasher<resident::Id>, const MAX: u32> Retirement<'_, 'id, T, H, MAX> {
pub fn occupied(&mut self, fresh: Fresh<'id, MAX>) -> resident::Occupied<'_, T, H, MAX> {
resident::Occupied {
table: self.table,
bucket: None,
index: fresh.key.slot(),
}
}
}
const _: () = {
assert!(std::mem::size_of::<Lease<'static, { u32::MAX }>>() == 8);
assert!(std::mem::size_of::<Option<Fresh<'static, { u32::MAX }>>>() == 8);
};