Skip to main content

hamon/
step.rs

1//! The representation of the Pipeline in system.
2//!
3//! Steps are processing units where each of them contributes a lot to the final outcome.
4//!
5use crate::errors::Result;
6use crate::{
7    utils::{FromStep, StepIndex, StepIndexBase},
8    Collector, Decorator,
9};
10use std::marker::PhantomData;
11
12#[doc(hidden)]
13pub struct FirstStep<T>(pub(crate) T);
14
15impl<T> Collector<T> for FirstStep<T> {
16    fn collect(self) -> Result<T> {
17        Ok(self.0)
18    }
19}
20
21/// Represent an active stage in the transformation pipeline.
22#[must_use = "Steps do nothing unless you consume (collect) them"]
23pub struct Step<D, P, T, ID> {
24    pub(crate) decorator: D,
25    pub(crate) previous: P,
26    pub(crate) _previous_type: PhantomData<T>,
27    pub(crate) _index: ID,
28}
29
30impl<D, P, T, ID> Step<D, P, T, ID> {
31    /// Applies a transformation to the current value and potentially changes existing type
32    ///
33    /// However, the transformation is lazy which means it only takes effect after you consume [`Step`] value.
34    /// Typical `step` registrations would be simply stacked up to produce a chain of step pipeline.
35    pub fn step<NewD, T1, T2>(self, decorator: NewD) -> Step<NewD, Self, T1, StepIndex<ID>>
36    where
37        NewD: Decorator<T1, T2>,
38        D: Decorator<T, T1>,
39    {
40        Step {
41            decorator,
42            previous: self,
43            _previous_type: PhantomData,
44            _index: StepIndex(PhantomData),
45        }
46    }
47
48    /// Provide the depth for the current `step`. At any time you can query where the current step's at.
49    pub fn get_index(&self) -> usize
50    where
51        ID: StepIndexBase,
52    {
53        ID::ID
54    }
55}
56
57impl<D, P, T, ID, O> Collector<O> for Step<D, P, T, ID>
58where
59    D: Decorator<T, O>,
60    P: Collector<T>,
61{
62    /// Finalizes the pipeline and returns the resulting value.
63    fn collect(mut self) -> Result<O> {
64        self.decorator.produce(self.previous.collect()?)
65    }
66}
67
68/// GuardedStep for ordered-matter pipeline system.
69///
70/// Unlike the typical step, this special is equipped with the ability to detect any up-front constraints
71///
72/// With respect to Rust Philosophy "Make illegal states unrepresentable", by bounding we can ensure only eligible states (STEPS)
73/// being instantiated.
74pub struct GuardedStep<D, P, T, ID> {
75    pub(crate) decorator: D,
76    pub(crate) previous: P,
77    pub(crate) _previous_type: PhantomData<T>,
78    pub(crate) _index: ID,
79}
80
81impl<D, P, T, ID> GuardedStep<D, P, T, ID> {
82    /// Applies a transformation to the current value and potentially changes existing type
83    ///
84    /// However, the transformation is lazy which means it only takes effect after you consume [`Step`] value.
85    /// Typical `step` registrations would be simply stacked up to produce a chain of step pipeline.
86    pub fn step<NewD, T1, T2>(self, decorator: NewD) -> GuardedStep<NewD, Self, T1, StepIndex<ID>>
87    where
88        NewD: Decorator<T1, T2> + FromStep<D>,
89        D: Decorator<T, T1>,
90    {
91        // Here we creata a type bound. From the Transition from D -> NewD
92        // The type NewD must provide the implemenation for trait marker FromStep with the
93        // particular type of D
94        // By that way the strong bond will be enforced.
95        GuardedStep {
96            decorator,
97            previous: self,
98            _previous_type: PhantomData,
99            _index: StepIndex(PhantomData),
100        }
101    }
102
103    /// Provide the depth for the current `step`. At any time you can query where the current step's at.
104    pub fn get_index(&self) -> usize
105    where
106        ID: StepIndexBase,
107    {
108        ID::ID
109    }
110}
111
112impl<D, P, T, ID, O> Collector<O> for GuardedStep<D, P, T, ID>
113where
114    D: Decorator<T, O>,
115    P: Collector<T>,
116{
117    /// Finalizes the pipeline and returns the resulting value.
118    fn collect(mut self) -> Result<O> {
119        self.decorator.produce(self.previous.collect()?)
120    }
121}