rings-core 0.20.0

Chord DHT implementation with ICE
Documentation
use std::sync::Arc;
use std::task::Context;
use std::task::Poll;

use futures::task::noop_waker;

use super::wait_queue::FairAdmission;
use super::wait_queue::FairWaiter;
use super::FairWaitBudget;
use super::FairWaitQueue;

fn queue(max_waiters: usize) -> Arc<FairWaitQueue> {
    Arc::new(FairWaitQueue::with_budget(Arc::new(FairWaitBudget::new(
        max_waiters,
        max_waiters,
    ))))
}

fn blocked_waiter(queue: &Arc<FairWaitQueue>) -> FairWaiter {
    match queue
        .admit_or_wait(1, (), || None::<()>)
        .expect("one waiter must fit the test budget")
    {
        FairAdmission::Ready(()) => panic!("a blocked attempt must enqueue"),
        FairAdmission::Waiting(waiter) => waiter,
    }
}

fn poll_waiter(waiter: &mut FairWaiter, value: usize) -> Poll<Option<usize>> {
    let waker = noop_waker();
    let mut context = Context::from_waker(&waker);
    waiter.poll(&mut context, || Some(value))
}

#[test]
fn test_wake_before_first_poll_is_retained() {
    let queue = queue(1);
    let mut waiter = blocked_waiter(&queue);

    queue.wake_front();

    assert_eq!(poll_waiter(&mut waiter, 7), Poll::Ready(Some(7)));
}

#[test]
fn test_cancelling_armed_front_hands_wake_to_successor() {
    let queue = queue(2);
    let first = blocked_waiter(&queue);
    let mut second = blocked_waiter(&queue);
    queue.wake_front();

    drop(first);

    assert_eq!(poll_waiter(&mut second, 2), Poll::Ready(Some(2)));
}

#[test]
fn test_cancelling_middle_preserves_fifo_release_order() {
    let queue = queue(3);
    let mut first = blocked_waiter(&queue);
    let middle = blocked_waiter(&queue);
    let mut third = blocked_waiter(&queue);
    drop(middle);
    queue.wake_front();

    assert_eq!(poll_waiter(&mut third, 3), Poll::Pending);
    assert_eq!(poll_waiter(&mut first, 1), Poll::Ready(Some(1)));
    assert_eq!(poll_waiter(&mut third, 3), Poll::Ready(Some(3)));
}

#[test]
fn test_cancelled_waiter_releases_shared_budget() {
    let queue = queue(1);
    let waiter = blocked_waiter(&queue);
    assert!(queue.admit_or_wait(1, (), || None::<()>).is_err());

    drop(waiter);

    assert!(matches!(
        queue.admit_or_wait(1, (), || None::<()>),
        Ok(FairAdmission::Waiting(_))
    ));
}