use o3::mem::quota;
pub trait Work {
type Graph;
}
pub trait Cycle: Copy + Eq {
const FIRST: Self;
fn next(self) -> Self;
}
#[repr(transparent)]
pub struct Arbiter<S: Cycle> {
cursor: S,
}
impl<S: Cycle> Arbiter<S> {
pub fn new() -> Self {
Self { cursor: S::FIRST }
}
pub fn take(&mut self) -> S {
let at = self.cursor;
self.account(at);
at
}
pub fn find(&self, mut ready: impl FnMut(S) -> bool) -> Option<S> {
let start = self.cursor;
let mut at = start;
loop {
if ready(at) {
return Some(at);
}
at = at.next();
if at == start {
return None;
}
}
}
pub fn select(&mut self, mut ready: impl FnMut(S) -> bool) -> Option<S> {
let at = self.find(&mut ready)?;
self.account(at);
Some(at)
}
pub fn admit<T>(
&mut self,
mut admit: impl FnMut(S) -> quota::Admission<T>,
) -> quota::Admission<T> {
let start = self.cursor;
let mut at = start;
loop {
match admit(at) {
quota::Admission::Item(item) => {
self.account(at);
return quota::Admission::Item(item);
}
quota::Admission::Empty => {}
quota::Admission::Exhausted => return quota::Admission::Exhausted,
}
at = at.next();
if at == start {
return quota::Admission::Empty;
}
}
}
pub fn account(&mut self, done: S) {
self.cursor = done.next();
}
}
impl<S: Cycle> Default for Arbiter<S> {
fn default() -> Self {
Self::new()
}
}