use std::{
sync::{Arc, PoisonError},
task::Wake,
};
use crate::sync::atomic::Ordering;
use super::super::GateState;
impl Wake for GateState {
fn wake(self: Arc<Self>) {
self.wake_by_ref();
}
fn wake_by_ref(self: &Arc<Self>) {
self.woke.store(true, Ordering::Release);
let waker = self
.waker
.lock()
.unwrap_or_else(PoisonError::into_inner)
.take();
if let Some(waker) = waker {
waker.wake();
}
}
}
#[cfg(test)]
mod tests {
use std::{
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
task::{Wake, Waker},
};
use super::super::super::GateState;
struct CountingWaker {
count: AtomicUsize,
}
impl Wake for CountingWaker {
fn wake(self: Arc<Self>) {
self.count.fetch_add(1, Ordering::Relaxed);
}
fn wake_by_ref(self: &Arc<Self>) {
self.count.fetch_add(1, Ordering::Relaxed);
}
}
fn counting_waker() -> (Arc<CountingWaker>, Waker) {
let inner = Arc::new(CountingWaker {
count: AtomicUsize::new(0),
});
let waker = Waker::from(inner.clone());
(inner, waker)
}
#[test]
fn wake_sets_the_request_and_notifies_the_stored_waker() {
let state = Arc::new(GateState::new());
assert!(state.take_wake_request());
assert!(!state.take_wake_request());
let (counter, waker) = counting_waker();
state.register(&waker);
let gate_waker = Waker::from(state.clone());
gate_waker.wake_by_ref();
assert!(state.take_wake_request());
assert_eq!(counter.count.load(Ordering::SeqCst), 1);
}
#[test]
fn repeated_wakes_without_a_repoll_notify_once() {
let state = Arc::new(GateState::new());
let (counter, waker) = counting_waker();
state.register(&waker);
let gate_waker = Waker::from(state);
gate_waker.wake_by_ref();
gate_waker.wake_by_ref();
gate_waker.wake();
assert_eq!(counter.count.load(Ordering::SeqCst), 1);
}
}