use crate::{
intrusive_double_linked_list::{LinkedList, ListNode},
utils::update_waker_ref,
NoopLock,
};
use core::pin::Pin;
use futures_core::{
future::{FusedFuture, Future},
task::{Context, Poll, Waker},
};
use lock_api::{Mutex, RawMutex};
#[derive(PartialEq)]
enum PollState {
New,
Waiting,
Done,
}
struct WaitQueueEntry {
task: Option<Waker>,
state: PollState,
}
impl WaitQueueEntry {
fn new() -> WaitQueueEntry {
WaitQueueEntry {
task: None,
state: PollState::New,
}
}
}
struct EventState {
is_set: bool,
waiters: LinkedList<WaitQueueEntry>,
}
impl EventState {
fn new(is_set: bool) -> EventState {
EventState {
is_set,
waiters: LinkedList::new(),
}
}
fn reset(&mut self) {
self.is_set = false;
}
fn set(&mut self) {
if self.is_set != true {
self.is_set = true;
self.waiters.reverse_drain(|waiter| {
if let Some(handle) = waiter.task.take() {
handle.wake();
}
waiter.state = PollState::Done;
});
}
}
fn is_set(&self) -> bool {
self.is_set
}
unsafe fn try_wait(
&mut self,
wait_node: &mut ListNode<WaitQueueEntry>,
cx: &mut Context<'_>,
) -> Poll<()> {
match wait_node.state {
PollState::New => {
if self.is_set {
wait_node.state = PollState::Done;
Poll::Ready(())
} else {
wait_node.task = Some(cx.waker().clone());
wait_node.state = PollState::Waiting;
self.waiters.add_front(wait_node);
Poll::Pending
}
}
PollState::Waiting => {
update_waker_ref(&mut wait_node.task, cx);
Poll::Pending
}
PollState::Done => {
Poll::Ready(())
}
}
}
fn remove_waiter(&mut self, wait_node: &mut ListNode<WaitQueueEntry>) {
if let PollState::Waiting = wait_node.state {
if !unsafe { self.waiters.remove(wait_node) } {
panic!("Future could not be removed from wait queue");
}
wait_node.state = PollState::Done;
}
}
}
pub struct GenericManualResetEvent<MutexType: RawMutex> {
inner: Mutex<MutexType, EventState>,
}
unsafe impl<MutexType: RawMutex + Send> Send
for GenericManualResetEvent<MutexType>
{
}
unsafe impl<MutexType: RawMutex + Sync> Sync
for GenericManualResetEvent<MutexType>
{
}
impl<MutexType: RawMutex> core::fmt::Debug
for GenericManualResetEvent<MutexType>
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("ManualResetEvent").finish()
}
}
impl<MutexType: RawMutex> GenericManualResetEvent<MutexType> {
pub fn new(is_set: bool) -> GenericManualResetEvent<MutexType> {
GenericManualResetEvent {
inner: Mutex::<MutexType, EventState>::new(EventState::new(is_set)),
}
}
pub fn set(&self) {
self.inner.lock().set()
}
pub fn reset(&self) {
self.inner.lock().reset()
}
pub fn is_set(&self) -> bool {
self.inner.lock().is_set()
}
pub fn wait(&self) -> GenericWaitForEventFuture<MutexType> {
GenericWaitForEventFuture {
event: Some(self),
wait_node: ListNode::new(WaitQueueEntry::new()),
}
}
unsafe fn try_wait(
&self,
wait_node: &mut ListNode<WaitQueueEntry>,
cx: &mut Context<'_>,
) -> Poll<()> {
self.inner.lock().try_wait(wait_node, cx)
}
fn remove_waiter(&self, wait_node: &mut ListNode<WaitQueueEntry>) {
self.inner.lock().remove_waiter(wait_node)
}
}
#[must_use = "futures do nothing unless polled"]
pub struct GenericWaitForEventFuture<'a, MutexType: RawMutex> {
event: Option<&'a GenericManualResetEvent<MutexType>>,
wait_node: ListNode<WaitQueueEntry>,
}
unsafe impl<'a, MutexType: RawMutex + Sync> Send
for GenericWaitForEventFuture<'a, MutexType>
{
}
impl<'a, MutexType: RawMutex> core::fmt::Debug
for GenericWaitForEventFuture<'a, MutexType>
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("GenericWaitForEventFuture").finish()
}
}
impl<'a, MutexType: RawMutex> Future
for GenericWaitForEventFuture<'a, MutexType>
{
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
let mut_self: &mut GenericWaitForEventFuture<MutexType> =
unsafe { Pin::get_unchecked_mut(self) };
let event = mut_self
.event
.expect("polled WaitForEventFuture after completion");
let poll_res = unsafe { event.try_wait(&mut mut_self.wait_node, cx) };
if let Poll::Ready(()) = poll_res {
mut_self.event = None;
}
poll_res
}
}
impl<'a, MutexType: RawMutex> FusedFuture
for GenericWaitForEventFuture<'a, MutexType>
{
fn is_terminated(&self) -> bool {
self.event.is_none()
}
}
impl<'a, MutexType: RawMutex> Drop
for GenericWaitForEventFuture<'a, MutexType>
{
fn drop(&mut self) {
if let Some(ev) = self.event {
ev.remove_waiter(&mut self.wait_node);
}
}
}
pub type LocalManualResetEvent = GenericManualResetEvent<NoopLock>;
pub type LocalWaitForEventFuture<'a> = GenericWaitForEventFuture<'a, NoopLock>;
#[cfg(feature = "std")]
mod if_std {
use super::*;
pub type ManualResetEvent = GenericManualResetEvent<parking_lot::RawMutex>;
pub type WaitForEventFuture<'a> =
GenericWaitForEventFuture<'a, parking_lot::RawMutex>;
}
#[cfg(feature = "std")]
pub use self::if_std::*;