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}