use std::cell::UnsafeCell;
use std::task::Waker;
const NUM_WAKERS: usize = 32;
pub(crate) struct SafeWakerCell {
waker: UnsafeCell<Option<Waker>>,
}
impl SafeWakerCell {
pub(crate) fn new() -> Self {
Self {
waker: UnsafeCell::new(None),
}
}
pub(crate) unsafe fn set_under_lock(&self, waker: Waker) {
*self.waker.get() = Some(waker);
}
pub(crate) unsafe fn take_under_lock(&self) -> Option<Waker> {
(*self.waker.get()).take()
}
pub(crate) unsafe fn wake_by_ref_under_lock(&self) {
if let Some(waker) = (*self.waker.get()).as_ref() {
waker.wake_by_ref();
}
}
pub(crate) unsafe fn has_waker_under_lock(&self) -> bool {
(*self.waker.get()).is_some()
}
}
unsafe impl Send for SafeWakerCell {}
unsafe impl Sync for SafeWakerCell {}
pub(crate) struct WakeList {
wakers: [Option<Waker>; NUM_WAKERS],
count: usize,
}
impl WakeList {
pub(crate) fn new() -> Self {
Self {
wakers: [const { None }; NUM_WAKERS],
count: 0,
}
}
pub(crate) fn can_push(&self) -> bool {
self.count < NUM_WAKERS
}
pub(crate) fn is_empty(&self) -> bool {
self.count == 0
}
pub(crate) fn was_full(&self) -> bool {
self.count == NUM_WAKERS
}
pub(crate) fn push(&mut self, waker: Waker) {
debug_assert!(self.can_push(), "WakeList is full");
self.wakers[self.count] = Some(waker);
self.count += 1;
}
pub(crate) unsafe fn push_unchecked(&mut self, waker: Waker) {
debug_assert!(self.can_push(), "WakeList is full");
*self.wakers.get_unchecked_mut(self.count) = Some(waker);
self.count += 1;
}
pub(crate) fn wake_all(&mut self) {
for i in 0..self.count {
if let Some(waker) = &self.wakers[i] {
waker.wake_by_ref();
}
}
for i in 0..self.count {
self.wakers[i] = None;
}
self.count = 0;
}
#[allow(dead_code)]
pub(crate) unsafe fn wake_all_unchecked(&mut self) {
for i in 0..self.count {
if let Some(waker) = self.wakers.get_unchecked_mut(i).take() {
waker.wake();
}
}
self.count = 0;
}
}