use std::{
task::{Context, Poll},
time::Duration,
};
use futures_core::Stream;
#[cfg(feature = "tracing")]
use crate::backend::ext::instrument::Instrumented;
use crate::{
backend::{
Backend, BackendConfig, WireFormatBackend,
codec::Codec,
ext::{
inspect_err::InspectErr,
interleave::Interleave,
lifecycle::{AfterStart, AfterStop, BeforeStart, BeforeStop},
map_err::MapErr,
pipe::Pipe,
poll_strategy::{PollStrategy, PollWith, StreamStrategy},
wake_on_push::WakeOnPush,
with_codec::WithCodec,
},
},
error::BoxDynError,
task::Task,
worker::context::WorkerContext,
};
#[cfg(feature = "shared")]
use crate::backend::ext::shared::Shared;
#[cfg(feature = "sleep")]
use crate::backend::ext::poll_strategy::{BackoffConfig, BackoffStrategy, IntervalStrategy};
#[macro_use]
pub mod delegate;
pub mod inspect_err;
#[cfg(feature = "tracing")]
pub mod instrument;
pub mod interleave;
pub mod map_err;
pub mod pipe;
pub mod poll_strategy;
pub mod wake_on_push;
pub mod with_codec;
pub mod lifecycle;
#[cfg(feature = "shared")]
pub mod shared;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum PollNextArgsError<B: Backend> {
#[error("backend error: {0}")]
BackendError(B::Error),
#[error("failed to decode task args: {0}")]
DecodeError(BoxDynError),
}
pub trait BackendExt: Backend {
#[allow(clippy::type_complexity)]
fn poll_next_args(
&mut self,
cx: &mut Context<'_>,
worker: &WorkerContext,
) -> Poll<Option<Result<Task<Self::Args>, PollNextArgsError<Self>>>>
where
Self: Sized + BackendConfig + WireFormatBackend + Backend<Task = Task<Self::Compact>>,
Self::Codec: Codec<Self::Args, Compact = Self::Compact>,
<Self::Codec as Codec<Self::Args>>::Error: std::error::Error + Send + Sync + 'static,
{
let next = self.poll_next(cx, worker);
let codec = self.codec();
next.map(move |item| match item {
Some(Ok(task)) => {
let task = task.try_map_args(|compact| codec.decode(&compact));
Some(task.map_err(|e| PollNextArgsError::DecodeError(e.into())))
}
Some(Err(e)) => Some(Err(PollNextArgsError::BackendError(e))),
None => None,
})
}
fn pipe_to<Dst>(self, backend: Dst) -> Pipe<Dst, Self>
where
Self: Sized,
{
Pipe::new(self, backend)
}
fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
where
Self: Sized,
F: Fn(&Self::Error),
{
InspectErr { backend: self, f }
}
fn map_err<F, E2>(self, f: F) -> MapErr<Self, F>
where
Self: Sized,
F: Fn(Self::Error) -> E2,
{
MapErr { backend: self, f }
}
fn with_codec<NewCodec>(self, codec: NewCodec) -> WithCodec<Self, NewCodec>
where
Self: Sized + BackendConfig,
NewCodec: Codec<Self::Args>,
{
WithCodec::new(self, codec)
}
fn poll_with_stream<S>(self, stream: S) -> PollWith<Self, StreamStrategy<S>>
where
Self: Sized,
S: Stream + Unpin + Send + 'static,
{
let strategy = StreamStrategy::new(stream);
PollWith::new(self, strategy)
}
#[cfg(feature = "sleep")]
fn poll_with_interval(self, duration: Duration) -> PollWith<Self, IntervalStrategy>
where
Self: Sized,
{
let strategy = IntervalStrategy::new(duration);
PollWith::new(self, strategy)
}
#[cfg(feature = "sleep")]
fn poll_with_backoff(
self,
interval: Duration,
config: BackoffConfig,
) -> PollWith<Self, BackoffStrategy>
where
Self: Sized,
{
let strategy = IntervalStrategy::new(interval).with_backoff(config);
PollWith::new(self, strategy)
}
fn poll_with_strategy<S>(self, strategy: S) -> PollWith<Self, S>
where
Self: Sized,
S: PollStrategy,
{
PollWith::new(self, strategy)
}
#[cfg(feature = "tracing")]
fn instrumented(self, span: tracing::Span) -> Instrumented<Self>
where
Self: Sized,
{
Instrumented::new(self, span)
}
fn before_start<F, Fut>(self, f: F) -> BeforeStart<Self, Self::Error>
where
Self: Sized,
F: Fn(&mut Self) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<(), Self::Error>> + Send + 'static,
{
BeforeStart::new(self, f)
}
fn before_stop<F, Fut>(self, f: F) -> BeforeStop<Self, Self::Error>
where
Self: Sized,
F: Fn(&mut Self) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<(), Self::Error>> + Send + 'static,
{
BeforeStop::new(self, f)
}
fn after_start<F, Fut>(self, f: F) -> AfterStart<Self, Self::Error>
where
Self: Sized,
for<'c> F: Fn(&mut Self) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<(), Self::Error>> + Send + 'static,
{
AfterStart::new(self, f)
}
fn after_stop<F, Fut>(self, f: F) -> AfterStop<Self, Self::Error>
where
Self: Sized,
F: Fn(&mut Self) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<(), Self::Error>> + Send + 'static,
{
AfterStop::new(self, f)
}
fn interleave<S>(self, stream: S) -> Interleave<Self, S>
where
Self: Sized,
S: Stream<Item = Result<Self::Task, Self::Error>> + Unpin,
{
Interleave::new(self, stream)
}
fn wake_on_push(self) -> WakeOnPush<Self>
where
Self: Sized,
{
WakeOnPush::new(self)
}
#[cfg(feature = "shared")]
fn shared(self) -> Shared<Self>
where
Self: WireFormatBackend + Send,
Self::Codec: Clone,
{
Shared::new(self)
}
}
impl<B: Backend> BackendExt for B {}