use core::pin::Pin;
use std::future::Future;
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll, Waker};
#[derive(Debug, Clone)]
pub struct BtlePlugFutureState<T> {
reply_msg: Option<T>,
waker: Option<Waker>,
completed: bool,
}
impl<T> Default for BtlePlugFutureState<T> {
fn default() -> Self {
BtlePlugFutureState::<T> {
reply_msg: None,
waker: None,
completed: false,
}
}
}
impl<T> BtlePlugFutureState<T> {
pub fn set_reply(&mut self, reply: T) {
if self.completed {
return;
}
self.completed = true;
self.reply_msg = Some(reply);
if let Some(waker) = self.waker.take() {
waker.wake();
}
}
}
pub type BtlePlugFutureStateShared<T> = Arc<Mutex<BtlePlugFutureState<T>>>;
#[derive(Debug)]
pub struct BtlePlugFuture<T> {
waker_state: BtlePlugFutureStateShared<T>,
}
impl<T> Default for BtlePlugFuture<T> {
fn default() -> Self {
BtlePlugFuture::<T> {
waker_state: BtlePlugFutureStateShared::<T>::default(),
}
}
}
impl<T> BtlePlugFuture<T> {
pub fn get_state_clone(&self) -> BtlePlugFutureStateShared<T> {
self.waker_state.clone()
}
}
impl<T> Future for BtlePlugFuture<T> {
type Output = T;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let mut waker_state = self.waker_state.lock().unwrap();
if waker_state.reply_msg.is_some() {
let msg = waker_state.reply_msg.take().unwrap();
Poll::Ready(msg)
} else {
waker_state.waker = Some(cx.waker().clone());
Poll::Pending
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::task::{Context, Poll, Waker};
#[test]
fn late_duplicate_completion_after_poll_is_ignored() {
let mut future = BtlePlugFuture::<u8>::default();
let state = future.get_state_clone();
let waker = Waker::noop();
let mut context = Context::from_waker(waker);
state.lock().unwrap().set_reply(1);
assert_eq!(Pin::new(&mut future).poll(&mut context), Poll::Ready(1));
state.lock().unwrap().set_reply(2);
assert!(matches!(
Pin::new(&mut future).poll(&mut context),
Poll::Pending
));
}
}