use slab::Slab;
#[derive(Debug)]
pub(crate) struct WaitList<T> {
guard: Option<usize>,
nodes: Slab<Node<T>>,
}
#[derive(Debug)]
struct Node<T> {
prev: usize,
next: usize,
stat: Option<T>,
}
impl<T> WaitList<T> {
fn ensure_init(&mut self) -> usize {
if let Some(guard) = self.guard {
return guard;
}
let first = self.nodes.vacant_entry();
let guard = first.key();
first.insert(Node {
prev: guard,
next: guard,
stat: None,
});
self.guard = Some(guard);
guard
}
pub(crate) const fn new() -> Self {
Self {
guard: None,
nodes: Slab::new(),
}
}
pub(crate) fn register_waiter_to_head(
&mut self,
idx: &mut Option<usize>,
f: impl FnOnce() -> Option<T>,
) {
assert!(idx.is_none());
let guard = self.ensure_init();
let stat = f();
let prev_head = self.nodes[guard].next;
let new_node = Node {
prev: guard,
next: prev_head,
stat,
};
let new_key = self.nodes.insert(new_node);
self.nodes[guard].next = new_key;
self.nodes[prev_head].prev = new_key;
*idx = Some(new_key);
}
pub(crate) fn register_waiter_to_tail(
&mut self,
idx: &mut Option<usize>,
f: impl FnOnce() -> Option<T>,
) {
assert!(idx.is_none());
let guard = self.ensure_init();
let stat = f();
let prev_tail = self.nodes[guard].prev;
let new_node = Node {
prev: prev_tail,
next: guard,
stat,
};
let new_key = self.nodes.insert(new_node);
self.nodes[guard].prev = new_key;
self.nodes[prev_tail].next = new_key;
*idx = Some(new_key);
}
pub(crate) fn remove_waiter(
&mut self,
idx: usize,
f: impl FnOnce(&mut T) -> bool,
) -> Option<&mut T> {
let guard = self.guard.expect("wait list must be uninitialized");
assert_ne!(idx, guard);
fn retrieve_stat<T>(node: &mut Node<T>) -> &mut T {
node.stat.as_mut().unwrap()
}
if f(retrieve_stat(&mut self.nodes[idx])) {
let prev = self.nodes[idx].prev;
let next = self.nodes[idx].next;
self.nodes[prev].next = next;
self.nodes[next].prev = prev;
self.nodes[idx].prev = idx;
self.nodes[idx].next = idx;
Some(retrieve_stat(&mut self.nodes[idx]))
} else {
None
}
}
pub(crate) fn remove_first_waiter(&mut self, f: impl FnOnce(&mut T) -> bool) -> Option<&mut T> {
let guard = self.guard?;
let first = self.nodes[guard].next;
if first != guard {
self.remove_waiter(first, f)
} else {
None
}
}
pub(crate) fn is_empty(&self) -> bool {
self.guard
.is_none_or(|guard| self.nodes[guard].next == guard)
}
pub(crate) fn with_mut(&mut self, idx: usize, drop: impl FnOnce(&mut T) -> bool) {
let node = &mut self.nodes[idx];
if drop(node.stat.as_mut().unwrap()) {
self.nodes.remove(idx);
}
}
}