#![allow(unsafe_code)]
use core::cell::UnsafeCell;
use core::marker::PhantomData;
use core::task::Waker;
const NIL: usize = usize::MAX;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct Key {
index: usize,
generation: u32,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum State {
Waiting,
Granted,
Closed,
Free,
}
struct Entry {
waker: Option<Waker>,
need: usize,
state: State,
prev: usize,
next: usize,
generation: u32,
}
struct Slab {
entries: Vec<Entry>,
free: usize,
head: usize,
tail: usize,
}
impl Slab {
const fn new() -> Self {
Self {
entries: Vec::new(),
free: NIL,
head: NIL,
tail: NIL,
}
}
fn live(&mut self, key: Key) -> Option<&mut Entry> {
self.entries
.get_mut(key.index)
.filter(|e| e.generation == key.generation && e.state != State::Free)
}
fn push(&mut self, need: usize, waker: Waker) -> Key {
let tail = self.tail;
let entry = Entry {
waker: Some(waker),
need,
state: State::Waiting,
prev: tail,
next: NIL,
generation: 0,
};
let index = if self.free == NIL {
self.entries.push(entry);
self.entries.len() - 1
} else {
let index = self.free;
let slot = &mut self.entries[index];
self.free = slot.next;
let generation = slot.generation;
*slot = Entry {
generation,
..entry
};
index
};
if tail == NIL {
self.head = index;
} else {
self.entries[tail].next = index;
}
self.tail = index;
Key {
index,
generation: self.entries[index].generation,
}
}
fn unlink(&mut self, index: usize) {
let (prev, next) = (self.entries[index].prev, self.entries[index].next);
if prev == NIL {
self.head = next;
} else {
self.entries[prev].next = next;
}
if next == NIL {
self.tail = prev;
} else {
self.entries[next].prev = prev;
}
}
fn free_entry(&mut self, index: usize) {
let free = self.free;
let slot = &mut self.entries[index];
slot.state = State::Free;
slot.waker = None;
slot.generation = slot.generation.wrapping_add(1);
slot.next = free;
self.free = index;
}
fn pop_front(&mut self, state: State) -> Option<(usize, Option<Waker>)> {
let index = self.head;
if index == NIL {
return None;
}
self.unlink(index);
let entry = &mut self.entries[index];
entry.state = state;
Some((entry.need, entry.waker.take()))
}
}
pub(crate) struct Waiters {
slab: UnsafeCell<Slab>,
_shard: PhantomData<*mut ()>,
}
impl Waiters {
pub(crate) const fn new() -> Self {
Self {
slab: UnsafeCell::new(Slab::new()),
_shard: PhantomData,
}
}
#[inline]
fn step<R>(&self, f: impl FnOnce(&mut Slab) -> R) -> R {
f(unsafe { &mut *self.slab.get() })
}
pub(crate) fn is_empty(&self) -> bool {
self.step(|s| s.head == NIL)
}
pub(crate) fn push(&self, need: usize, waker: Waker) -> Key {
self.step(|s| s.push(need, waker))
}
pub(crate) fn grant_front_if(&self, available: usize) -> Option<(usize, Option<Waker>)> {
self.step(|s| {
if s.head != NIL && s.entries[s.head].need <= available {
s.pop_front(State::Granted)
} else {
None
}
})
}
pub(crate) fn close_front(&self) -> Option<Option<Waker>> {
self.step(|s| s.pop_front(State::Closed).map(|(_, waker)| waker))
}
pub(crate) fn refresh(&self, key: Key, waker: &Waker) -> State {
let (state, same) = self.step(|s| {
s.live(key).map_or((State::Free, true), |e| {
(
e.state,
e.state != State::Waiting
|| e.waker.as_ref().is_some_and(|w| w.will_wake(waker)),
)
})
});
if !same {
let fresh = waker.clone();
let old = self.step(|s| match s.live(key) {
Some(e) if e.state == State::Waiting => e.waker.replace(fresh),
_ => Some(fresh),
});
drop(old);
}
state
}
pub(crate) fn take(&self, key: Key) {
self.step(|s| {
if s.live(key).is_some_and(|e| e.state != State::Waiting) {
s.free_entry(key.index);
}
});
}
pub(crate) fn cancel(&self, key: Key) -> (State, bool, Option<Waker>) {
self.step(|s| {
let Some(entry) = s.live(key) else {
return (State::Free, false, None);
};
let state = entry.state;
let waker = entry.waker.take();
let was_front = state == State::Waiting && s.head == key.index;
if state == State::Waiting {
s.unlink(key.index);
}
s.free_entry(key.index);
(state, was_front, waker)
})
}
}