use std::future::Future;
use std::pin::pin;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{mpsc, Arc, Barrier};
use std::task::{Context, Poll, Wake, Waker};
use std::thread;
use std::time::Duration;
use rsignals::r#async::{create, Disconnected, NoReceivers, TryWaitError};
const MANY: usize = 12;
struct ThreadWaker(thread::Thread);
impl Wake for ThreadWaker {
fn wake(self: Arc<Self>) {
self.0.unpark();
}
fn wake_by_ref(self: &Arc<Self>) {
self.0.unpark();
}
}
fn block_on<F: Future>(future: F) -> F::Output {
let mut future = pin!(future);
let waker = Waker::from(Arc::new(ThreadWaker(thread::current())));
let mut cx = Context::from_waker(&waker);
loop {
match future.as_mut().poll(&mut cx) {
Poll::Ready(v) => return v,
Poll::Pending => thread::park(),
}
}
}
struct CountWaker(Arc<AtomicUsize>);
impl Wake for CountWaker {
fn wake(self: Arc<Self>) {
self.0.fetch_add(1, Ordering::SeqCst);
}
fn wake_by_ref(self: &Arc<Self>) {
self.0.fetch_add(1, Ordering::SeqCst);
}
}
fn counting_waker() -> (Waker, Arc<AtomicUsize>) {
let count = Arc::new(AtomicUsize::new(0));
(Waker::from(Arc::new(CountWaker(count.clone()))), count)
}
#[test]
fn await_completes_after_later_signal() {
let (tx, rx) = create();
let (send, recv) = mpsc::channel();
thread::spawn(move || {
let _ = send.send(block_on(rx.wait()));
});
assert!(recv.recv_timeout(Duration::from_millis(80)).is_err());
assert_eq!(tx.signal(), Ok(true));
assert_eq!(
recv.recv_timeout(Duration::from_secs(5)).unwrap(),
Ok(()),
"awaiter must complete after the signal"
);
}
#[test]
fn await_after_signal_is_immediate() {
let (tx, rx) = create();
assert_eq!(tx.signal(), Ok(true));
assert_eq!(block_on(rx.wait()), Ok(()));
}
#[test]
fn many_awaiters_released_by_one_signal() {
let (tx, rx) = create();
let barrier = Arc::new(Barrier::new(MANY + 1));
let (send, recv) = mpsc::channel();
for _ in 0..MANY {
let rx = rx.clone();
let barrier = barrier.clone();
let send = send.clone();
thread::spawn(move || {
barrier.wait();
let _ = send.send(block_on(rx.wait()));
});
}
drop(send);
barrier.wait();
thread::sleep(Duration::from_millis(30));
assert_eq!(tx.signal(), Ok(true));
for _ in 0..MANY {
assert_eq!(recv.recv_timeout(Duration::from_secs(5)).unwrap(), Ok(()));
}
}
#[test]
fn await_disconnects_when_all_signalers_dropped() {
let (tx, rx) = create();
let (send, recv) = mpsc::channel();
thread::spawn(move || {
let _ = send.send(block_on(rx.wait()));
});
thread::sleep(Duration::from_millis(80));
drop(tx);
assert_eq!(
recv.recv_timeout(Duration::from_secs(5)).unwrap(),
Err(Disconnected),
"awaiter must be released with Disconnected"
);
}
#[test]
fn signal_reports_no_receivers() {
let (tx, rx) = create();
drop(rx);
assert_eq!(tx.signal(), Err(NoReceivers));
assert!(!tx.is_signaled());
}
#[test]
fn snapshots_track_state() {
let (tx, rx) = create();
assert_eq!(rx.try_wait(), Err(TryWaitError::Pending));
assert!(!rx.is_signaled());
assert!(!rx.is_disconnected());
assert_eq!(tx.signal(), Ok(true));
assert_eq!(rx.try_wait(), Ok(()));
assert!(rx.is_signaled());
}
#[test]
fn try_wait_reports_disconnected() {
let (tx, rx) = create();
drop(tx);
assert!(rx.is_disconnected());
assert_eq!(rx.try_wait(), Err(TryWaitError::Disconnected));
}
#[test]
fn counts_track_clones() {
let (tx, rx) = create();
assert_eq!(tx.signaler_count(), 1);
assert_eq!(tx.waiter_count(), 1);
let tx2 = tx.clone();
let rx2 = rx.clone();
assert_eq!(rx.signaler_count(), 2);
assert_eq!(tx.waiter_count(), 2);
drop(tx2);
drop(rx2);
assert_eq!(rx.signaler_count(), 1);
assert_eq!(tx.waiter_count(), 1);
}
#[test]
fn poll_registers_waker_and_signal_wakes_it() {
let (tx, rx) = create();
let (waker, count) = counting_waker();
let mut cx = Context::from_waker(&waker);
let mut fut = pin!(rx.wait());
assert_eq!(fut.as_mut().poll(&mut cx), Poll::Pending);
assert_eq!(count.load(Ordering::SeqCst), 0, "no wake before signal");
assert_eq!(tx.signal(), Ok(true));
assert!(
count.load(Ordering::SeqCst) >= 1,
"signal must wake the registered waker"
);
assert_eq!(fut.as_mut().poll(&mut cx), Poll::Ready(Ok(())));
}
#[test]
fn poll_registers_waker_and_disconnect_wakes_it() {
let (tx, rx) = create();
let (waker, count) = counting_waker();
let mut cx = Context::from_waker(&waker);
let mut fut = pin!(rx.wait());
assert_eq!(fut.as_mut().poll(&mut cx), Poll::Pending);
drop(tx);
assert!(
count.load(Ordering::SeqCst) >= 1,
"disconnect must wake the registered waker"
);
assert_eq!(fut.as_mut().poll(&mut cx), Poll::Ready(Err(Disconnected)));
}
#[test]
fn cancelling_a_pending_future_is_safe() {
let (tx, rx) = create();
{
let (waker, _count) = counting_waker();
let mut cx = Context::from_waker(&waker);
let mut fut = pin!(rx.wait());
assert_eq!(fut.as_mut().poll(&mut cx), Poll::Pending);
}
let rx2 = rx.clone();
let h = thread::spawn(move || block_on(rx2.wait()));
thread::sleep(Duration::from_millis(30));
assert_eq!(tx.signal(), Ok(true));
assert_eq!(h.join().unwrap(), Ok(()));
}
#[test]
fn repeated_await_after_fire() {
let (tx, rx) = create();
assert_eq!(tx.signal(), Ok(true));
for _ in 0..MANY {
assert_eq!(block_on(rx.wait()), Ok(()));
}
}