use alloc::sync::Arc;
use self::{optional::OptionalLayer, stack::Stack, then::Then};
use super::{
AddData, BoxContextOperator, Context, ContextOperator, ContextOperatorExt, Insert, InsertData,
InsertWithData, Inspect, RefOperator,
};
pub mod cache;
pub mod insert;
pub mod inspect;
pub mod data;
pub mod stack;
pub mod then;
pub mod optional;
pub trait Layer<In, P>
where
P: ContextOperator<In>,
{
type Operator: ContextOperator<In, Out = Self::Out>;
type Out;
fn layer(&self, operator: P) -> Self::Operator;
}
#[derive(Debug, Clone, Copy)]
pub struct LayerFn<F>(F);
impl<F, In, P, P2> Layer<In, P> for LayerFn<F>
where
F: Fn(P) -> P2,
P: ContextOperator<In>,
P2: ContextOperator<In>,
{
type Operator = P2;
type Out = P2::Out;
#[inline]
fn layer(&self, operator: P) -> Self::Operator {
(self.0)(operator)
}
}
pub fn layer_fn<F>(f: F) -> LayerFn<F> {
LayerFn(f)
}
pub trait LayerExt<In, P>: Layer<In, P>
where
P: ContextOperator<In>,
{
fn boxed(self) -> BoxLayer<P, In, Self::Out>
where
Self: Sized + Send + Sync + 'static,
Self::Operator: Send + 'static,
{
BoxLayer::new(self)
}
#[inline]
fn with<Outer>(self, outer: Outer) -> Stack<Self, Outer>
where
Outer: Layer<In, Self::Operator>,
Self: Sized,
{
Stack(self, outer)
}
fn insert_env<R, Out, F>(self, f: F) -> Stack<Self, Insert<F>>
where
F: Fn() -> R,
R: for<'a> RefOperator<'a, In, Output = Out>,
Out: Send + Sync + 'static,
Self: Sized,
{
self.with(Insert(f))
}
fn insert_env_if<R, Out, F>(self, enable: bool, f: F) -> Stack<Self, OptionalLayer<Insert<F>>>
where
F: Fn() -> R,
R: for<'a> RefOperator<'a, In, Output = Out>,
Out: Send + Sync + 'static,
Self: Sized,
{
self.with_if(if enable { Some(Insert(f)) } else { None })
}
fn insert_data<R, Out, F>(self, f: F) -> Stack<Self, InsertData<F>>
where
F: Fn() -> R,
R: for<'a> RefOperator<'a, In, Output = Option<Out>>,
Out: Send + Sync + 'static,
Self: Sized,
{
self.with(InsertData(f))
}
fn insert_data_if<R, Out, F>(
self,
enable: bool,
f: F,
) -> Stack<Self, OptionalLayer<InsertData<F>>>
where
F: Fn() -> R,
R: for<'a> RefOperator<'a, In, Output = Option<Out>>,
Out: Send + Sync + 'static,
Self: Sized,
{
self.with_if(if enable { Some(InsertData(f)) } else { None })
}
fn insert<R, Env, Data, F>(self, f: F) -> Stack<Self, InsertWithData<F>>
where
F: Fn() -> R,
R: for<'a> RefOperator<'a, In, Output = (Env, Option<Data>)>,
Env: Send + Sync + 'static,
Data: Send + Sync + 'static,
Self: Sized,
{
self.with(InsertWithData(f))
}
fn insert_if<R, Env, Data, F>(
self,
enable: bool,
f: F,
) -> Stack<Self, OptionalLayer<InsertWithData<F>>>
where
F: Fn() -> R,
R: for<'a> RefOperator<'a, In, Output = (Env, Option<Data>)>,
Env: Send + Sync + 'static,
Data: Send + Sync + 'static,
Self: Sized,
{
self.with_if(if enable {
Some(InsertWithData(f))
} else {
None
})
}
fn inspect<F>(self, f: F) -> Stack<Self, Inspect<F>>
where
F: Fn(&In, &Context) + Clone,
Self: Sized,
{
self.with(Inspect(f))
}
fn provide<D>(self, data: D) -> Stack<Self, AddData<D>>
where
D: Clone + Send + Sync + 'static,
Self: Sized,
{
self.with(AddData::with_data(data))
}
fn provide_if<D>(self, data: Option<D>) -> Stack<Self, OptionalLayer<AddData<D>>>
where
D: Clone + Send + Sync + 'static,
Self: Sized,
{
self.with_if(data.map(AddData::with_data))
}
fn provide_with<D>(
self,
provider: impl Fn() -> Option<D> + Send + Sync + 'static,
) -> Stack<Self, AddData<D>>
where
D: Send + Sync + 'static,
Self: Sized,
{
self.with(AddData::new(provider))
}
fn provide_with_if<D>(
self,
enable: bool,
provider: impl Fn() -> Option<D> + Send + Sync + 'static,
) -> Stack<Self, OptionalLayer<AddData<D>>>
where
D: Send + Sync + 'static,
Self: Sized,
{
self.with_if(if enable {
Some(AddData::new(provider))
} else {
None
})
}
#[allow(clippy::wrong_self_convention)]
#[deprecated(note = "use `data_from_context` instead")]
fn from_context<D>(self) -> Stack<Self, AddData<D>>
where
D: Send + Sync + 'static,
Self: Sized,
{
self.with(AddData::<D>::from_context())
}
fn data_from_context<D>(self) -> Stack<Self, AddData<D>>
where
D: Send + Sync + 'static,
Self: Sized,
{
self.with(AddData::<D>::from_context())
}
fn then_with<Out, F, Builder>(self, builder: Builder) -> Stack<Self, Then<Builder>>
where
Builder: Fn() -> F,
F: FnMut(Self::Out, &Context) -> Out + Clone,
Self: Sized,
{
self.with(Then(builder))
}
fn with_if<L>(self, layer: Option<L>) -> Stack<Self, OptionalLayer<L>>
where
L: Layer<In, Self::Operator>,
L::Operator: ContextOperator<In, Out = Self::Out>,
Self: Sized,
{
self.with(OptionalLayer(layer))
}
}
impl<In, P, L> LayerExt<In, P> for L
where
P: ContextOperator<In>,
L: Layer<In, P>,
{
}
pub struct BoxLayer<P, In, Out> {
inner: Arc<
dyn Layer<In, P, Operator = BoxContextOperator<In, Out>, Out = Out> + Send + Sync + 'static,
>,
}
impl<P, In, Out> BoxLayer<P, In, Out> {
pub fn new<L>(inner: L) -> Self
where
P: ContextOperator<In>,
L: Layer<In, P, Out = Out> + Send + Sync + 'static,
L::Operator: Send + 'static,
{
let layer = layer_fn(move |op: P| inner.layer(op).boxed());
Self {
inner: Arc::new(layer),
}
}
}
impl<P, In, Out> Layer<In, P> for BoxLayer<P, In, Out>
where
P: ContextOperator<In>,
{
type Operator = BoxContextOperator<In, Out>;
type Out = Out;
fn layer(&self, operator: P) -> Self::Operator {
self.inner.layer(operator)
}
}