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,
        }
    }
}