use std::{pin::Pin, task::Poll};
use futures_core::Future;
#[derive(Debug)]
pub(crate) struct AcknowledgedMessage<M, R = ()> {
acknowledger: AcknowledgmentSender<R>,
message: M,
}
impl<M, R> AcknowledgedMessage<M, R> {
pub(crate) fn package(message: M) -> (Self, AcknowledgmentReceiver<R>) {
let (sender, receiver) = tokio::sync::oneshot::channel();
(
Self {
message,
acknowledger: AcknowledgmentSender { sender },
},
AcknowledgmentReceiver { receiver },
)
}
pub(crate) fn acknowledge(self, result: impl Into<R>) {
self.acknowledger.acknowledge(result)
}
pub(crate) fn into_parts(self) -> (M, AcknowledgmentSender<R>) {
(self.message, self.acknowledger)
}
}
impl<M, R> std::ops::Deref for AcknowledgedMessage<M, R> {
type Target = M;
fn deref(&self) -> &Self::Target {
&self.message
}
}
#[derive(Debug)]
pub(crate) struct AcknowledgmentSender<R> {
sender: tokio::sync::oneshot::Sender<R>,
}
impl<R> AcknowledgmentSender<R> {
pub(crate) fn acknowledge(self, result: impl Into<R>) {
let _: std::result::Result<_, _> = self.sender.send(result.into());
}
}
pub(crate) struct AcknowledgmentReceiver<R> {
receiver: tokio::sync::oneshot::Receiver<R>,
}
impl<R> AcknowledgmentReceiver<R> {
pub(crate) async fn wait_for_acknowledgment(self) -> Option<R> {
self.receiver.await.ok()
}
}
impl<R> Future for AcknowledgmentReceiver<R> {
type Output = Option<R>;
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
match Pin::new(&mut self.get_mut().receiver).poll(cx) {
Poll::Ready(r) => Poll::Ready(r.ok()),
Poll::Pending => Poll::Pending,
}
}
}