use std::{
future::Future,
ops::{Deref, DerefMut},
pin::Pin,
task::{Context, Poll},
};
use crate::Waiter;
pub trait Pollable: Unpin {
type Output;
fn poll(&self, waiter: &Waiter) -> Poll<Self::Output>;
}
pub struct Pending<P> {
inner: P,
waiter: Option<Waiter>,
}
impl<P> Pending<P> {
pub fn new(inner: P) -> Self {
Self { inner, waiter: None }
}
pub fn into_inner(self) -> P {
self.inner
}
}
impl<P> Deref for Pending<P> {
type Target = P;
fn deref(&self) -> &P {
&self.inner
}
}
impl<P> DerefMut for Pending<P> {
fn deref_mut(&mut self) -> &mut P {
&mut self.inner
}
}
impl<P: Pollable> Future for Pending<P> {
type Output = P::Output;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<P::Output> {
let this = &mut *self;
this.waiter = Some(Waiter::new(cx.waker().clone()));
Pollable::poll(&this.inner, this.waiter.as_ref().unwrap())
}
}
#[cfg(all(test, not(loom)))]
mod test {
use super::*;
use crate::Producer;
struct AtLeast {
consumer: crate::Consumer<u64>,
threshold: u64,
}
impl AtLeast {
fn bump_threshold(&mut self) {
self.threshold += 1;
}
}
impl Pollable for AtLeast {
type Output = u64;
fn poll(&self, waiter: &Waiter) -> Poll<u64> {
let threshold = self.threshold;
match self.consumer.poll(waiter, |v| {
let current = **v;
if current >= threshold {
Poll::Ready(current)
} else {
Poll::Pending
}
}) {
Poll::Ready(Ok(v)) => Poll::Ready(v),
_ => Poll::Pending,
}
}
}
#[test]
fn pending_derefs_and_drives() {
use std::task::Waker;
let producer = Producer::new(0u64);
let mut pending = Pending::new(AtLeast {
consumer: producer.consume(),
threshold: 5,
});
pending.bump_threshold();
assert!(Pollable::poll(&*pending, &Waiter::noop()).is_pending());
if let Ok(mut v) = producer.write() {
*v = 6;
}
let mut cx = Context::from_waker(Waker::noop());
let mut pending = std::pin::pin!(pending);
assert_eq!(Future::poll(pending.as_mut(), &mut cx), Poll::Ready(6));
}
}