use core::marker::PhantomData;
use std::{mem, ops};
use o3::mem::{Lease, Return, lease::Open};
use crate::{
driver,
driver::{
life, route,
route::{lease, queues},
},
};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Error {
Occupied,
}
const _: () = assert!(std::mem::size_of::<Error>() == 0);
pub(crate) struct Registry {
live: [u64; route::CAPACITY / u64::BITS as usize],
}
pub(in crate::driver::route) struct Reserved<'d, B: route::App> {
brand: PhantomData<B>,
driver: driver::Reference<'d>,
}
impl Registry {
pub(crate) const fn new() -> Self {
Self {
live: [0; route::CAPACITY / u64::BITS as usize],
}
}
pub(in crate::driver) fn release<'d>(
local: &mut life::Local<'d>,
retired: queues::Retired<'d>,
) {
let id = retired.into_id();
local.routes.live[id.raw() as usize / 64] &= !(1u64 << (id.raw() % 64));
}
}
impl<'d, B: route::App> Reserved<'d, B> {
pub(super) fn try_new(local: &mut life::Local<'d>) -> Result<Self, lease::Error> {
let id = <B as route::App>::ID;
let word = id.raw() as usize / 64;
let mask = 1u64 << (id.raw() % 64);
if local.routes.live[word] & mask != 0 {
return Err(lease::Error::Occupied);
}
local.routes.live[word] |= mask;
Ok(Self {
driver: local.driver,
brand: PhantomData,
})
}
pub(in crate::driver::route) fn driver(&self) -> driver::Reference<'d> {
self.driver
}
pub(super) fn release(self, driver: &mut driver::Context<'_, 'd>) {
driver.storage.release(queues::Retired::reserved(self));
}
}
impl<B: route::App> Return for Reserved<'_, B> {
type Item = ();
fn return_item(self, (): Self::Item) {
queues::Pending::defer(self);
}
}
pub struct Claim<'d, B: route::App> {
driver: Lease<Reserved<'d, B>, Open>,
}
impl<'d, B: route::App> Claim<'d, B> {
pub(in crate::driver) fn try_new(local: &mut life::Local<'d>) -> Result<Self, Error> {
Ok(Self {
driver: Lease::open(Reserved::try_new(local)?, ()),
})
}
pub fn into_owner(self) -> Owner<'d, B> {
self.store(())
}
pub fn store<T>(self, value: T) -> Owner<'d, B, T> {
Owner { value, claim: self }
}
pub fn driver(&self) -> driver::Reference<'d> {
self.driver.sink().driver()
}
pub fn next_generation(&self) -> Option<route::Epoch> {
self.driver().shared.context().generations[<B as route::App>::ID.raw() as usize].get()
}
pub fn rollback(self, driver: &mut driver::Context<'_, 'd>) {
let (reserved, ()) = self.driver.into_parts();
reserved.release(driver);
}
}
const _: () = {
let word = mem::size_of::<usize>();
assert!(mem::size_of::<Claim<'static, route::KeyTag<0>>>() == word);
assert!(mem::size_of::<Option<Claim<'static, route::KeyTag<0>>>>() == word);
};
pub struct Owner<'d, B: route::App, T = ()> {
value: T,
claim: Claim<'d, B>,
}
impl<'d, B: route::App> Owner<'d, B> {
pub fn try_reserve<'a, 'c>(
driver: &'a mut driver::Context<'c, 'd>,
) -> Result<Vacant<'a, 'c, 'd, B>, Error> {
let local = &mut *driver.storage.0;
let claim = Claim::try_new(local)?;
Ok(Vacant::new(claim, driver))
}
pub fn release(self, driver: &mut driver::Context<'_, 'd>) {
self.claim.rollback(driver);
}
}
impl<'d, B: route::App, T> Owner<'d, B, T> {
pub fn driver(&self) -> driver::Reference<'d> {
self.claim.driver()
}
pub fn advance_to(&self, floor: Option<route::Epoch>) {
let next =
&self.driver().shared.context().generations[<B as route::App>::ID.raw() as usize];
next.set(
next.get()
.zip(floor)
.map(|(current, floor)| current.max(floor)),
);
}
}
impl<B: route::App, T> ops::Deref for Owner<'_, B, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
const _: () = {
assert!(mem::size_of::<Owner<'static, route::KeyTag<0>>>() == mem::size_of::<usize>());
assert!(mem::align_of::<Owner<'static, route::KeyTag<0>>>() == mem::align_of::<usize>());
assert!(
mem::size_of::<Owner<'static, route::KeyTag<0>, usize>>()
== mem::size_of::<(Owner<'static, route::KeyTag<0>>, usize)>()
);
};
pub struct Vacant<'a, 'c, 'd, B: route::App> {
hold: Lease<Rollback<'a, 'c, 'd, B>, Open>,
}
struct Rollback<'a, 'c, 'd, B: route::App>(&'a mut driver::Context<'c, 'd>, PhantomData<B>);
impl<'a, 'c, 'd, B: route::App> Vacant<'a, 'c, 'd, B> {
pub(in crate::driver) fn new(
hold: Claim<'d, B>,
driver: &'a mut driver::Context<'c, 'd>,
) -> Self {
Self {
hold: Lease::open(Rollback(driver, PhantomData), hold),
}
}
pub fn driver(&mut self) -> &mut driver::Context<'c, 'd> {
self.hold.parts_mut().0.0
}
pub fn commit(self) -> Owner<'d, B> {
self.into_claim().into_owner()
}
pub fn into_claim(self) -> Claim<'d, B> {
self.hold.into_parts().1
}
}
impl<'d, B: route::App> Return for Rollback<'_, '_, 'd, B> {
type Item = Claim<'d, B>;
fn return_item(self, hold: Self::Item) {
hold.rollback(self.0);
}
}
const _: () = {
let word = mem::size_of::<usize>();
assert!(mem::size_of::<Vacant<'static, 'static, 'static, route::KeyTag<0>>>() == 2 * word);
assert!(
mem::size_of::<Option<Vacant<'static, 'static, 'static, route::KeyTag<0>>>>() == 2 * word
);
};