indicator/context/layer/
mod.rs

1use alloc::sync::Arc;
2
3use self::{optional::OptionalLayer, stack::Stack, then::Then};
4
5use super::{
6    AddData, BoxContextOperator, Context, ContextOperator, ContextOperatorExt, Insert, InsertData,
7    InsertWithData, Inspect, RefOperator,
8};
9
10/// Layer that caches the final context,
11/// and provides it to the next evaluation.
12pub mod cache;
13
14/// Layer that inserts a value into the context.
15pub mod insert;
16
17/// Layer that used to inspect the context.
18pub mod inspect;
19
20/// Layer for manipulating the data context.
21pub mod data;
22
23/// Stack of layers.
24pub mod stack;
25
26/// Then layer.
27pub mod then;
28
29/// Optional layer.
30pub mod optional;
31
32/// Layer.
33/// Convert an [`ContextOperator`] to another [`ContextOperator`]
34pub trait Layer<In, P>
35where
36    P: ContextOperator<In>,
37{
38    /// The output operator.
39    type Operator: ContextOperator<In, Out = Self::Out>;
40
41    /// The output type.
42    type Out;
43
44    /// Convert an `In`-operator to another `In`-operator.
45    fn layer(&self, operator: P) -> Self::Operator;
46}
47
48/// Layer defined by a closure.
49#[derive(Debug, Clone, Copy)]
50pub struct LayerFn<F>(F);
51
52impl<F, In, P, P2> Layer<In, P> for LayerFn<F>
53where
54    F: Fn(P) -> P2,
55    P: ContextOperator<In>,
56    P2: ContextOperator<In>,
57{
58    type Operator = P2;
59    type Out = P2::Out;
60
61    #[inline]
62    fn layer(&self, operator: P) -> Self::Operator {
63        (self.0)(operator)
64    }
65}
66
67/// Create a layer from a closure.
68pub fn layer_fn<F>(f: F) -> LayerFn<F> {
69    LayerFn(f)
70}
71
72/// Extension trait for [`Layer`].
73pub trait LayerExt<In, P>: Layer<In, P>
74where
75    P: ContextOperator<In>,
76{
77    /// Create a boxed [`Layer`].
78    fn boxed(self) -> BoxLayer<P, In, Self::Out>
79    where
80        Self: Sized + Send + Sync + 'static,
81        Self::Operator: Send + 'static,
82    {
83        BoxLayer::new(self)
84    }
85
86    /// Stack a outer layer on top of the inner layer.
87    #[inline]
88    fn with<Outer>(self, outer: Outer) -> Stack<Self, Outer>
89    where
90        Outer: Layer<In, Self::Operator>,
91        Self: Sized,
92    {
93        Stack(self, outer)
94    }
95
96    /// Add a [`Insert`] layer with the given [`RefOperator`] constructor
97    /// (i.e. a function that returns a [`RefOperator`]).
98    ///
99    /// We use this method to add the output of the operator to the `env` context.
100    fn insert_env<R, Out, F>(self, f: F) -> Stack<Self, Insert<F>>
101    where
102        F: Fn() -> R,
103        R: for<'a> RefOperator<'a, In, Output = Out>,
104        Out: Send + Sync + 'static,
105        Self: Sized,
106    {
107        self.with(Insert(f))
108    }
109
110    /// Optionally add the [`Insert`] layer with the given [`RefOperator`] constructor.
111    ///
112    /// See [`insert_env`] for more details.
113    fn insert_env_if<R, Out, F>(self, enable: bool, f: F) -> Stack<Self, OptionalLayer<Insert<F>>>
114    where
115        F: Fn() -> R,
116        R: for<'a> RefOperator<'a, In, Output = Out>,
117        Out: Send + Sync + 'static,
118        Self: Sized,
119    {
120        self.with_if(if enable { Some(Insert(f)) } else { None })
121    }
122
123    /// Add a [`InsertData`] layer with the given [`RefOperator`] constructor.
124    /// (i.e. a function that returns a [`RefOperator`]).
125    ///
126    /// We use this method to add the output of the operator to the `data` context.
127    fn insert_data<R, Out, F>(self, f: F) -> Stack<Self, InsertData<F>>
128    where
129        F: Fn() -> R,
130        R: for<'a> RefOperator<'a, In, Output = Option<Out>>,
131        Out: Send + Sync + 'static,
132        Self: Sized,
133    {
134        self.with(InsertData(f))
135    }
136
137    /// Optionally add the [`InsertData`] layer with the given [`RefOperator`] constructor.
138    ///
139    /// See [`insert_data`] for more details.
140    fn insert_data_if<R, Out, F>(
141        self,
142        enable: bool,
143        f: F,
144    ) -> Stack<Self, OptionalLayer<InsertData<F>>>
145    where
146        F: Fn() -> R,
147        R: for<'a> RefOperator<'a, In, Output = Option<Out>>,
148        Out: Send + Sync + 'static,
149        Self: Sized,
150    {
151        self.with_if(if enable { Some(InsertData(f)) } else { None })
152    }
153
154    /// Add a [`InsertWithData`] layer with the given [`RefOperator`] constructor.
155    /// (i.e. a function that returns a [`RefOperator`]).
156    ///
157    /// We use this method to add the output of the operator to the `env` and `data` context simultaneously.
158    fn insert<R, Env, Data, F>(self, f: F) -> Stack<Self, InsertWithData<F>>
159    where
160        F: Fn() -> R,
161        R: for<'a> RefOperator<'a, In, Output = (Env, Option<Data>)>,
162        Env: Send + Sync + 'static,
163        Data: Send + Sync + 'static,
164        Self: Sized,
165    {
166        self.with(InsertWithData(f))
167    }
168
169    /// Optionally add the [`InsertWithData`] layer with the given [`RefOperator`] constructor.
170    ///
171    /// See [`insert`] for more details.
172    fn insert_if<R, Env, Data, F>(
173        self,
174        enable: bool,
175        f: F,
176    ) -> Stack<Self, OptionalLayer<InsertWithData<F>>>
177    where
178        F: Fn() -> R,
179        R: for<'a> RefOperator<'a, In, Output = (Env, Option<Data>)>,
180        Env: Send + Sync + 'static,
181        Data: Send + Sync + 'static,
182        Self: Sized,
183    {
184        self.with_if(if enable {
185            Some(InsertWithData(f))
186        } else {
187            None
188        })
189    }
190
191    /// Add an inspect layer with the given closure.
192    fn inspect<F>(self, f: F) -> Stack<Self, Inspect<F>>
193    where
194        F: Fn(&In, &Context) + Clone,
195        Self: Sized,
196    {
197        self.with(Inspect(f))
198    }
199
200    /// Provide data to the context.
201    fn provide<D>(self, data: D) -> Stack<Self, AddData<D>>
202    where
203        D: Clone + Send + Sync + 'static,
204        Self: Sized,
205    {
206        self.with(AddData::with_data(data))
207    }
208
209    /// Optionally provide data to the context.
210    ///
211    /// If the data is `None`, the layer will be skipped,
212    /// so will not panic if the data is not in the context.
213    fn provide_if<D>(self, data: Option<D>) -> Stack<Self, OptionalLayer<AddData<D>>>
214    where
215        D: Clone + Send + Sync + 'static,
216        Self: Sized,
217    {
218        self.with_if(data.map(AddData::with_data))
219    }
220
221    /// Provide data to the context with the given data provider.
222    fn provide_with<D>(
223        self,
224        provider: impl Fn() -> Option<D> + Send + Sync + 'static,
225    ) -> Stack<Self, AddData<D>>
226    where
227        D: Send + Sync + 'static,
228        Self: Sized,
229    {
230        self.with(AddData::new(provider))
231    }
232
233    /// Optionally provide data to the context with the given data provider.
234    ///
235    /// If not enabled, the layer will be skipped,
236    /// so will not panic if the data is not in the context.
237    fn provide_with_if<D>(
238        self,
239        enable: bool,
240        provider: impl Fn() -> Option<D> + Send + Sync + 'static,
241    ) -> Stack<Self, OptionalLayer<AddData<D>>>
242    where
243        D: Send + Sync + 'static,
244        Self: Sized,
245    {
246        self.with_if(if enable {
247            Some(AddData::new(provider))
248        } else {
249            None
250        })
251    }
252
253    /// Declare that the data of type `D` is in the context.
254    // FIXME: this method should be removed in the future.
255    #[allow(clippy::wrong_self_convention)]
256    #[deprecated(note = "use `data_from_context` instead")]
257    fn from_context<D>(self) -> Stack<Self, AddData<D>>
258    where
259        D: Send + Sync + 'static,
260        Self: Sized,
261    {
262        self.with(AddData::<D>::from_context())
263    }
264
265    /// Declare that the data of type `D` is in the data context.
266    fn data_from_context<D>(self) -> Stack<Self, AddData<D>>
267    where
268        D: Send + Sync + 'static,
269        Self: Sized,
270    {
271        self.with(AddData::<D>::from_context())
272    }
273
274    /// Add a closure that will be called after the operator is evaluated.
275    fn then_with<Out, F, Builder>(self, builder: Builder) -> Stack<Self, Then<Builder>>
276    where
277        Builder: Fn() -> F,
278        F: FnMut(Self::Out, &Context) -> Out + Clone,
279        Self: Sized,
280    {
281        self.with(Then(builder))
282    }
283
284    /// Optionally add a layer.
285    fn with_if<L>(self, layer: Option<L>) -> Stack<Self, OptionalLayer<L>>
286    where
287        L: Layer<In, Self::Operator>,
288        L::Operator: ContextOperator<In, Out = Self::Out>,
289        Self: Sized,
290    {
291        self.with(OptionalLayer(layer))
292    }
293}
294
295impl<In, P, L> LayerExt<In, P> for L
296where
297    P: ContextOperator<In>,
298    L: Layer<In, P>,
299{
300}
301
302/// A boxed [`Layer`].
303pub struct BoxLayer<P, In, Out> {
304    inner: Arc<
305        dyn Layer<In, P, Operator = BoxContextOperator<In, Out>, Out = Out> + Send + Sync + 'static,
306    >,
307}
308
309impl<P, In, Out> BoxLayer<P, In, Out> {
310    /// Create a boxed [`Layer`].
311    pub fn new<L>(inner: L) -> Self
312    where
313        P: ContextOperator<In>,
314        L: Layer<In, P, Out = Out> + Send + Sync + 'static,
315        L::Operator: Send + 'static,
316    {
317        let layer = layer_fn(move |op: P| inner.layer(op).boxed());
318        Self {
319            inner: Arc::new(layer),
320        }
321    }
322}
323
324impl<P, In, Out> Layer<In, P> for BoxLayer<P, In, Out>
325where
326    P: ContextOperator<In>,
327{
328    type Operator = BoxContextOperator<In, Out>;
329
330    type Out = Out;
331
332    fn layer(&self, operator: P) -> Self::Operator {
333        self.inner.layer(operator)
334    }
335}