use super::{
NotificationEvent, NotificationFailureKind, NotificationSubscriptionError, SubscriptionInbox,
};
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
pub(in crate::notifications) struct InboxWait<'a> {
inbox: &'a SubscriptionInbox,
registered: bool,
}
impl<'a> InboxWait<'a> {
pub(super) fn new(inbox: &'a SubscriptionInbox) -> Self {
Self {
inbox,
registered: false,
}
}
}
impl Future for InboxWait<'_> {
type Output = Result<Option<NotificationEvent>, NotificationSubscriptionError>;
fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
let next_waker = context.waker().clone();
let mut state = this.inbox.state.lock();
if !this.registered && state.async_waiting {
return Poll::Ready(Err(NotificationSubscriptionError::new(
NotificationFailureKind::InvalidRequest,
)));
}
let result = match state.poll(&this.inbox.identity, &this.inbox.memory) {
Ok(Poll::Pending) => Poll::Pending,
Ok(Poll::Ready(event)) => Poll::Ready(Ok(event)),
Err(error) => Poll::Ready(Err(error)),
};
let previous = if result.is_pending() {
state.async_waiting = true;
this.registered = true;
state.async_waker.replace(next_waker)
} else {
state.async_waiting = false;
this.registered = false;
state.async_waker.take()
};
drop(state);
drop(previous);
result
}
}
impl Drop for InboxWait<'_> {
fn drop(&mut self) {
if self.registered {
let mut state = self.inbox.state.lock();
state.async_waiting = false;
let waker = state.async_waker.take();
drop(state);
drop(waker);
}
}
}