notify-future 0.2.6

Support asynchronous notification completion future
Documentation
use std::future::Future;
use std::pin::Pin;
use std::sync::{
    atomic::{AtomicUsize, Ordering},
    Arc,
};
use std::task::{Context, Poll, Waker};

use notify_future::Notify;
#[allow(deprecated)]
use notify_future::NotifyFuture;

struct DropCounter {
    drops: Arc<AtomicUsize>,
}

impl Drop for DropCounter {
    fn drop(&mut self) {
        self.drops.fetch_add(1, Ordering::SeqCst);
    }
}

fn noop_waker() -> &'static Waker {
    Waker::noop()
}

#[allow(deprecated)]
#[test]
fn notify_future_ready_after_set_complete_on_production_cfg() {
    let mut notify_future = NotifyFuture::<u32>::new();
    let notifier = notify_future.clone();

    notifier.set_complete(1);

    let mut cx = Context::from_waker(noop_waker());
    let value = match Pin::new(&mut notify_future).poll(&mut cx) {
        Poll::Ready(value) => value,
        Poll::Pending => panic!("future remained pending after set_complete"),
    };

    assert_eq!(value, 1);
}

#[test]
fn notify_waiter_ready_after_notify_on_production_cfg() {
    let (notify, mut waiter) = Notify::<u32>::new();

    notify.notify(1);

    let mut cx = Context::from_waker(noop_waker());
    let value = match Pin::new(&mut waiter).poll(&mut cx) {
        Poll::Ready(value) => value,
        Poll::Pending => panic!("waiter remained pending after notify"),
    };

    assert_eq!(value, 1);
}

#[test]
fn ready_value_is_dropped_if_waiter_is_dropped_on_production_cfg() {
    let drops = Arc::new(AtomicUsize::new(0));
    let (notify, waiter) = Notify::<DropCounter>::new();

    notify.notify(DropCounter {
        drops: drops.clone(),
    });
    drop(waiter);

    assert_eq!(drops.load(Ordering::SeqCst), 1);
}

#[test]
fn notify_after_waiter_drop_discards_result_on_production_cfg() {
    let drops = Arc::new(AtomicUsize::new(0));
    let (notify, waiter) = Notify::<DropCounter>::new();

    drop(waiter);
    assert!(notify.is_canceled());

    notify.notify(DropCounter {
        drops: drops.clone(),
    });

    assert_eq!(drops.load(Ordering::SeqCst), 1);
}

#[allow(deprecated)]
#[test]
fn repeated_notify_future_set_complete_drops_losing_input_on_production_cfg() {
    let drops = Arc::new(AtomicUsize::new(0));
    let mut notify_future = NotifyFuture::<DropCounter>::new();
    let notifier = notify_future.clone();

    notifier.set_complete(DropCounter {
        drops: drops.clone(),
    });
    notifier.set_complete(DropCounter {
        drops: drops.clone(),
    });

    let mut cx = Context::from_waker(noop_waker());
    let value = match Pin::new(&mut notify_future).poll(&mut cx) {
        Poll::Ready(value) => value,
        Poll::Pending => panic!("future remained pending after set_complete"),
    };

    assert_eq!(drops.load(Ordering::SeqCst), 1);
    drop(value);
    assert_eq!(drops.load(Ordering::SeqCst), 2);
}