use std::num::NonZero;
use o3::{
base::cell::region,
mem::{self, lease},
};
use crate::driver::{
schedule,
schedule::{app, app::batch, state::lanes},
};
pub mod raw;
#[must_use = "dropping a batch reservation returns all of its quota"]
pub struct Reserved<'turn, 'd, T> {
quota: lanes::Quota<'turn, 'd, lease::Open>,
limit: T,
}
#[must_use = "a batch bound must be converted into an unused proof"]
pub struct Bound<'id, T> {
limit: T,
token: region::Token<region::Identity<'id>>,
}
impl<'turn, 'd, T: batch::raw::Limit> Reserved<'turn, 'd, T> {
pub fn reserve(work: app::Work<'turn, 'd>, limit: T, prior: bool) -> schedule::Capacity<Self> {
let reserved = limit.get().get() - 1 + usize::from(prior);
match lanes::Quota::reserve_app(work, reserved) {
schedule::Capacity::Available(quota) => {
schedule::Capacity::Available(Self { quota, limit })
}
schedule::Capacity::Exhausted => schedule::Capacity::Exhausted,
}
}
pub fn with<C, R>(
self,
context: C,
apply: impl for<'id> FnOnce(C, Bound<'id, T>) -> (R, mem::raw::Unused<'id>),
) -> R {
let Self {
quota: reserved,
limit,
} = self;
reserved
.inner
.with((context, limit), |(context, limit), token| {
apply(context, Bound { limit, token })
})
}
}
impl<'id, T: batch::raw::Limit> Bound<'id, T> {
pub fn get(&self) -> &T {
&self.limit
}
pub fn empty(self) -> mem::raw::Unused<'id> {
unsafe { mem::raw::Unused::new(self.limit.get().get() - 1, self.token) }
}
fn into_parts(self) -> (T, region::Token<region::Identity<'id>>) {
(self.limit, self.token)
}
}
const _: () = {
let word = size_of::<usize>();
assert!(size_of::<Reserved<'static, 'static, NonZero<usize>>>() == 3 * word);
assert!(size_of::<Bound<'static, NonZero<usize>>>() == word);
};