use super::append_response::AppendResponse;
use super::error::{AppendError, AppendResult};
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::sync::oneshot;
#[derive(Debug)]
pub struct AppendFuture {
rx: oneshot::Receiver<AppendResult<AppendResponse>>,
}
impl AppendFuture {
#[allow(dead_code)]
pub(crate) fn new(rx: oneshot::Receiver<AppendResult<AppendResponse>>) -> Self {
Self { rx }
}
}
impl Future for AppendFuture {
type Output = AppendResult<AppendResponse>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let result = std::task::ready!(Pin::new(&mut self.rx).poll(cx));
match result {
Ok(res) => Poll::Ready(res),
Err(_) => Poll::Ready(Err(AppendError::UnexpectedEndOfStream)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::model::TableSchema;
#[tokio::test]
async fn happy_path() {
let (tx, rx) = oneshot::channel();
let _ = tx.send(Ok(AppendResponse {
offset: None,
updated_schema: Some(TableSchema::default()),
}));
let future = AppendFuture::new(rx);
let resp = future.await.expect("should succeed");
assert_eq!(resp.offset, None);
assert_eq!(resp.updated_schema, Some(TableSchema::default()));
}
#[tokio::test]
async fn dropped_sender() {
let (tx, rx) = oneshot::channel::<AppendResult<AppendResponse>>();
drop(tx);
let future = AppendFuture::new(rx);
let err = future
.await
.expect_err("should return unexpected end of stream");
assert!(matches!(err, AppendError::UnexpectedEndOfStream));
}
#[tokio::test]
async fn channel_returns_error() {
let (tx, rx) = oneshot::channel();
let _ = tx.send(Err(AppendError::UnexpectedEndOfStream));
let future = AppendFuture::new(rx);
let err = future.await.expect_err("should return error from task");
assert!(matches!(err, AppendError::UnexpectedEndOfStream));
}
}