use std::{
pin::Pin,
task::{Context, Poll},
};
use crate::{
backend::{
Backend, BackendConfig, WireFormatBackend,
codec::Codec,
finalize::{Durable, Ephemeral},
},
error::BoxDynError,
task::{Task, builder::TaskBuilder},
};
use futures_channel::mpsc::SendError;
use futures_core::Stream;
use futures_sink::Sink;
use futures_util::SinkExt;
use futures_util::StreamExt;
use futures_util::stream;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum TaskSinkError<PushError> {
#[error("Failed to push task: {0}")]
PushError(#[from] PushError),
#[error("Failed to encode/decode task: {0}")]
CodecError(BoxDynError),
#[error("Failed to send new task: {0}")]
SendError(SendError),
}
pub trait TaskSink<Args, Kind>: Backend {
fn start_send(self: Pin<&mut Self>, item: Task<Args>)
-> Result<(), TaskSinkError<Self::Error>>;
fn poll_ready(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), TaskSinkError<Self::Error>>>;
fn poll_flush(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), TaskSinkError<Self::Error>>>;
fn poll_close(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), TaskSinkError<Self::Error>>>;
fn push(
&mut self,
task: Args,
) -> impl Future<Output = Result<(), TaskSinkError<Self::Error>>> + Send;
fn push_bulk(
&mut self,
tasks: Vec<Args>,
) -> impl Future<Output = Result<(), TaskSinkError<Self::Error>>> + Send;
fn push_stream(
&mut self,
tasks: impl Stream<Item = Args> + Unpin + Send,
) -> impl Future<Output = Result<(), TaskSinkError<Self::Error>>> + Send;
fn push_task(
&mut self,
task: Task<Args>,
) -> impl Future<Output = Result<(), TaskSinkError<Self::Error>>> + Send;
fn push_all(
&mut self,
tasks: impl Stream<Item = Task<Args>> + Unpin + Send,
) -> impl Future<Output = Result<(), TaskSinkError<Self::Error>>> + Send;
}
impl<Args, S, E, C> TaskSink<Args, Durable> for S
where
S: Sink<Task<C::Compact>, Error = E>
+ Unpin
+ Backend<Error = E>
+ WireFormatBackend<Codec = C>
+ BackendConfig<Args = Args, Kind = Durable>
+ Send,
Args: Send,
C::Compact: Send,
C: Codec<Args> + Clone + Send + Sync,
E: Send,
C::Error: std::error::Error + Send + Sync + 'static,
{
fn start_send(
self: Pin<&mut Self>,
item: Task<Args>,
) -> Result<(), TaskSinkError<Self::Error>> {
let codec = self.codec();
let task = item.try_map_args(|t| {
codec
.encode(&t)
.map_err(|e| TaskSinkError::CodecError(e.into()))
})?;
Sink::start_send(self, task).map_err(|e| TaskSinkError::PushError(e))
}
fn poll_ready(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), TaskSinkError<Self::Error>>> {
Sink::poll_ready(self, cx).map_err(|e| TaskSinkError::PushError(e))
}
fn poll_flush(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), TaskSinkError<Self::Error>>> {
Sink::poll_flush(self, cx).map_err(|e| TaskSinkError::PushError(e))
}
fn poll_close(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), TaskSinkError<Self::Error>>> {
Sink::poll_close(self, cx).map_err(|e| TaskSinkError::PushError(e))
}
async fn push(&mut self, task: Args) -> Result<(), TaskSinkError<Self::Error>> {
use futures_util::SinkExt;
let encoded = self
.codec()
.encode(&task)
.map_err(|e| TaskSinkError::CodecError(e.into()))?;
self.send(TaskBuilder::new(encoded).build()).await?;
Ok(())
}
async fn push_bulk(&mut self, tasks: Vec<Args>) -> Result<(), TaskSinkError<Self::Error>> {
use futures_util::SinkExt;
let tasks = tasks
.into_iter()
.map(TaskBuilder::new)
.map(|task| {
task.try_map_args(|t| {
self.codec()
.encode(&t)
.map_err(|e| TaskSinkError::CodecError(e.into()))
})
.map(|t| t.build())
})
.collect::<Result<Vec<_>, _>>()?;
self.send_all(&mut stream::iter(tasks.into_iter().map(Ok)))
.await?;
Ok(())
}
async fn push_stream(
&mut self,
tasks: impl Stream<Item = Args> + Unpin + Send,
) -> Result<(), TaskSinkError<Self::Error>> {
let codec = self.codec().clone();
self.sink_map_err(|e| TaskSinkError::PushError(e))
.send_all(&mut tasks.map(TaskBuilder::new).map(|task| {
task.try_map_args(|t| {
codec
.encode(&t)
.map_err(|e| TaskSinkError::CodecError(e.into()))
})
.map(|t| t.build())
}))
.await
}
async fn push_task(&mut self, task: Task<Args>) -> Result<(), TaskSinkError<Self::Error>> {
use futures_util::SinkExt;
let codec = self.codec();
let task = task.try_map_args(|t| {
codec
.encode(&t)
.map_err(|e| TaskSinkError::CodecError(e.into()))
})?;
self.sink_map_err(|e| TaskSinkError::PushError(e))
.send(task)
.await
}
async fn push_all(
&mut self,
tasks: impl Stream<Item = Task<Args>> + Unpin + Send,
) -> Result<(), TaskSinkError<Self::Error>> {
use futures_util::SinkExt;
let codec = self.codec().clone();
let mut encoded = tasks.map(|task| {
task.try_map_args(|t| {
codec
.encode(&t)
.map_err(|e| TaskSinkError::CodecError(e.into()))
})
});
self.sink_map_err(|e| TaskSinkError::PushError(e))
.send_all(&mut encoded)
.await
}
}
impl<Args, S, E> TaskSink<Args, Ephemeral> for S
where
S: Sink<Task<Args>, Error = E>
+ Unpin
+ Backend<Error = E>
+ BackendConfig<Args = Args, Kind = Ephemeral>
+ Send,
Args: Send,
E: Send,
{
fn start_send(
self: Pin<&mut Self>,
item: Task<Args>,
) -> Result<(), TaskSinkError<Self::Error>> {
Sink::start_send(self, item).map_err(|e| TaskSinkError::PushError(e))
}
fn poll_ready(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), TaskSinkError<Self::Error>>> {
Sink::poll_ready(self, cx).map_err(|e| TaskSinkError::PushError(e))
}
fn poll_flush(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), TaskSinkError<Self::Error>>> {
Sink::poll_flush(self, cx).map_err(|e| TaskSinkError::PushError(e))
}
fn poll_close(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), TaskSinkError<Self::Error>>> {
Sink::poll_close(self, cx).map_err(|e| TaskSinkError::PushError(e))
}
async fn push(&mut self, args: Args) -> Result<(), TaskSinkError<Self::Error>> {
let task = TaskBuilder::new(args).build();
self.send(task)
.await
.map_err(|e| TaskSinkError::PushError(e))
}
async fn push_bulk(&mut self, tasks: Vec<Args>) -> Result<(), TaskSinkError<Self::Error>> {
let tasks = tasks
.into_iter()
.map(TaskBuilder::new)
.map(|t| Ok::<_, E>(t.build()))
.collect::<Result<Vec<_>, _>>()?;
self.send_all(&mut stream::iter(tasks.into_iter().map(Ok)))
.await
.map_err(|e| TaskSinkError::PushError(e))?;
Ok(())
}
async fn push_stream(
&mut self,
tasks: impl Stream<Item = Args> + Unpin + Send,
) -> Result<(), TaskSinkError<Self::Error>> {
self.sink_map_err(|e| TaskSinkError::PushError(e))
.send_all(&mut tasks.map(TaskBuilder::new).map(|task| Ok(task.build())))
.await
}
async fn push_task(&mut self, task: Task<Args>) -> Result<(), TaskSinkError<Self::Error>> {
use futures_util::SinkExt;
self.sink_map_err(|e| TaskSinkError::PushError(e))
.send(task)
.await
}
async fn push_all(
&mut self,
tasks: impl Stream<Item = Task<Args>> + Unpin + Send,
) -> Result<(), TaskSinkError<Self::Error>> {
use futures_util::SinkExt;
self.sink_map_err(|e| TaskSinkError::PushError(e))
.send_all(&mut tasks.map(Ok))
.await
}
}