use futures_util::task::AtomicWaker;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::task::Context;
#[derive(Clone, Debug, Default)]
pub struct CancelHandle(Arc<Signal>);
#[derive(Debug, Default)]
struct Signal {
requested: AtomicBool,
waker: AtomicWaker,
}
impl CancelHandle {
pub fn cancel(&self) {
self.0.requested.store(true, Ordering::Release);
self.0.waker.wake();
}
pub(crate) fn poll_requested(&self, cx: &mut Context<'_>) -> bool {
self.0.waker.register(cx.waker());
self.0.requested.load(Ordering::Acquire)
}
pub(crate) fn clear(&self) {
self.0.requested.store(false, Ordering::Release);
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::AtomicUsize;
use std::task::{Wake, Waker};
struct CountWakes(AtomicUsize);
impl Wake for CountWakes {
fn wake(self: Arc<Self>) {
self.0.fetch_add(1, Ordering::SeqCst);
}
}
#[test]
fn cancel_wakes_the_reader_and_stays_pending_until_cleared() {
let wakes = Arc::new(CountWakes(AtomicUsize::new(0)));
let waker = Waker::from(Arc::clone(&wakes));
let mut cx = Context::from_waker(&waker);
let handle = CancelHandle::default();
assert!(!handle.poll_requested(&mut cx));
handle.clone().cancel();
assert_eq!(1, wakes.0.load(Ordering::SeqCst));
assert!(handle.poll_requested(&mut cx));
handle.clear();
assert!(!handle.poll_requested(&mut cx));
}
}