use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::sync::oneshot::Receiver;
use zb_hw::HwResponse;
use crate::Error;
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct InternalCommunicationResponse<T> {
hw_response: Option<HwResponse>,
response: Receiver<T>,
}
impl<T> InternalCommunicationResponse<T> {
pub const fn new(hw_response: HwResponse, response: Receiver<T>) -> Self {
Self {
hw_response: Some(hw_response),
response,
}
}
}
impl<T> Future for InternalCommunicationResponse<T> {
type Output = Result<T, Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
if let Some(hw_response) = this.hw_response.as_mut() {
match Pin::new(hw_response).poll(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(Ok(())) => this.hw_response = None,
Poll::Ready(Err(error)) => return Poll::Ready(Err(error.into())),
}
}
match Pin::new(&mut this.response).poll(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(Ok(result)) => Poll::Ready(Ok(result)),
Poll::Ready(Err(error)) => Poll::Ready(Err(error.into())),
}
}
}
#[cfg(test)]
mod tests {
use std::future::Future;
use std::pin::pin;
use std::task::{Context, Poll, Waker};
use tokio::sync::oneshot::channel;
use zb_hw::{Error, HwResponse};
use super::InternalCommunicationResponse;
const RESPONSE: u8 = 42;
#[test]
fn waits_for_the_protocol_response_after_transmission() {
let (sender, receiver) = channel();
let hw_response = HwResponse::new(async { Ok::<(), Error>(()) });
let mut response = pin!(InternalCommunicationResponse::new(hw_response, receiver));
let mut context = Context::from_waker(Waker::noop());
assert!(matches!(
response.as_mut().poll(&mut context),
Poll::Pending
));
assert_eq!(sender.send(RESPONSE), Ok(()));
assert!(matches!(
response.as_mut().poll(&mut context),
Poll::Ready(Ok(RESPONSE))
));
}
#[test]
fn returns_a_hardware_error_without_waiting_for_the_protocol_response() {
let (_sender, receiver) = channel::<u8>();
let hw_response = HwResponse::new(async { Err::<(), _>(Error::NotImplemented) });
let mut response = pin!(InternalCommunicationResponse::new(hw_response, receiver));
let mut context = Context::from_waker(Waker::noop());
assert!(matches!(
response.as_mut().poll(&mut context),
Poll::Ready(Err(crate::Error::Hardware(Error::NotImplemented)))
));
}
}