rock_n_rollup/core/
service.rs

1use super::{RawInput, Runtime};
2
3#[derive(Clone)]
4pub struct Input<P> {
5    pub level: u32,
6    pub id: u32,
7    pub payload: P,
8}
9
10pub trait FromInput<P, S>
11where
12    Self: Sized,
13{
14    fn from_input<R: Runtime>(runtime: &mut R, input: &Input<P>, state: &S) -> Result<Self, ()>;
15}
16
17////////// some types
18type TransitionFct<R, P, S> = dyn FnMut(&mut R, &Input<P>, &S) -> Result<(), ()>;
19
20type GuardFct<R, P> = dyn FnMut(&mut R, &Input<P>) -> bool;
21
22pub trait IntoTransition<R, P, S, T>
23where
24    R: Runtime,
25{
26    fn into_transition(self) -> Box<TransitionFct<R, P, S>>;
27}
28
29// Macro to implements IntoTransition for any function of n parameter
30macro_rules! tuple_from_req {
31    ($struct_name:ident; $($generic_param:ident),*) => {
32        #[allow(non_snake_case)]
33        pub struct $struct_name<$($generic_param),*> {
34            $( $generic_param: $generic_param ),*
35        }
36
37        impl<P, S, $($generic_param),*> FromInput<P, S> for $struct_name<$($generic_param),*>
38        where
39            $($generic_param: FromInput<P, S>),*,
40            P: Clone,
41        {
42            fn from_input<R: Runtime>(runtime: &mut R, input: &Input<P>, state: &S) -> Result<Self, ()> {
43                $(
44                    #[allow(non_snake_case)]
45                    let $generic_param = match <$generic_param>::from_input(runtime, input, state) {
46                        Ok(t) => t,
47                        Err(_) => return Err(()),
48                    };
49                )*
50
51                Ok($struct_name { $($generic_param),* })
52            }
53        }
54
55        impl<R, P, Fct, S, $($generic_param),*> IntoTransition<R, P, S, $struct_name<$($generic_param),*>> for Fct
56            where
57                R: Runtime,
58                Fct: Fn(&mut R, $($generic_param),*) + 'static,
59                $($generic_param: FromInput<P, S>),*,
60                P: Clone,
61        {
62            fn into_transition(self) -> Box<dyn FnMut(&mut R, &Input<P>, &S) -> Result<(), ()>> {
63                Box::new(move |runtime: &mut R, input: &Input<P>, state: &S| {
64                    let tuple = match $struct_name::from_input(runtime, input, state) {
65                        Ok(t) => t,
66                        Err(_) => return Err(()),
67                    };
68                    (self)(runtime, $(tuple.$generic_param),*);
69                    Ok(())
70                })
71            }
72        }
73    };
74}
75
76impl<R, P, F, S> IntoTransition<R, P, S, ()> for F
77where
78    R: Runtime,
79    F: Fn(&mut R) + 'static,
80{
81    fn into_transition(self) -> Box<dyn FnMut(&mut R, &Input<P>, &S) -> Result<(), ()>> {
82        println!("Into transition");
83        Box::new(move |runtime: &mut R, _: &Input<P>, _: &S| {
84            (self)(runtime);
85            Ok(())
86        })
87    }
88}
89
90tuple_from_req!(Tuple1; A);
91tuple_from_req!(Tuple2; A, B);
92tuple_from_req!(Tuple3; A, B, C);
93tuple_from_req!(Tuple4; A, B, C, D);
94tuple_from_req!(Tuple5; A, B, C, D, E);
95tuple_from_req!(Tuple6; A, B, C, D, E, F);
96tuple_from_req!(Tuple7; A, B, C, D, E, F, G);
97tuple_from_req!(Tuple8; A, B, C, D, E, F, G, H);
98tuple_from_req!(Tuple9; A, B, C, D, E, F, G, H, I);
99
100///// FromInput implementation
101pub trait FromRawInput
102where
103    Self: Sized,
104{
105    fn from_raw_input<R: Runtime>(runtime: &mut R, input: &RawInput) -> Result<Self, ()>;
106}
107
108impl<S> FromInput<Vec<u8>, S> for () {
109    fn from_input<R: Runtime>(_: &mut R, _: &Input<Vec<u8>>, _: &S) -> Result<Self, ()> {
110        Ok(())
111    }
112}
113
114impl<P, S> FromInput<P, S> for Input<P>
115where
116    P: Clone,
117{
118    fn from_input<R: Runtime>(_: &mut R, input: &Input<P>, _: &S) -> Result<Self, ()> {
119        Ok(input.clone())
120    }
121}
122
123impl<P, S> FromInput<P, S> for P
124where
125    P: Clone,
126{
127    fn from_input<R: Runtime>(_: &mut R, input: &Input<P>, _: &S) -> Result<Self, ()> {
128        Ok(input.payload.clone())
129    }
130}
131
132impl FromRawInput for Vec<u8> {
133    fn from_raw_input<R: Runtime>(_: &mut R, input: &RawInput) -> Result<Self, ()> {
134        Ok(input.payload.clone())
135    }
136}
137
138impl FromRawInput for () {
139    fn from_raw_input<R: Runtime>(_: &mut R, _: &RawInput) -> Result<Self, ()> {
140        Ok(())
141    }
142}
143
144////// Service
145
146pub struct Service<R, P, S>
147where
148    P: FromRawInput,
149{
150    guards: Vec<Box<GuardFct<R, P>>>,
151    transitions: Vec<Box<TransitionFct<R, P, S>>>,
152    state: S,
153}
154
155impl<R, P, S> Service<R, P, S>
156where
157    P: FromRawInput,
158{
159    pub fn new(state: S) -> Self {
160        Self {
161            guards: Default::default(),
162            transitions: Default::default(),
163            state,
164        }
165    }
166}
167
168pub trait Runnable<R>
169where
170    R: Runtime,
171{
172    fn run(&mut self, runtime: &mut R, input: RawInput);
173}
174
175impl<R, P, S> Runnable<R> for Service<R, P, S>
176where
177    R: Runtime,
178    P: FromRawInput,
179{
180    fn run(&mut self, runtime: &mut R, input: RawInput) {
181        println!("run");
182
183        let payload = match P::from_raw_input(runtime, &input) {
184            Ok(payload) => payload,
185            Err(_) => todo!("handle this error"),
186        };
187        println!("payload is present");
188
189        // Get the raw input
190        let input = Input {
191            level: input.level,
192            id: input.id,
193            payload,
194        };
195
196        // Get the "state"
197        let state = &self.state;
198
199        // Run the guards
200        let accepted = self.guards.iter_mut().all(|guard| guard(runtime, &input));
201
202        match accepted {
203            false => {
204                println!("hmmmm");
205                // Do nothing on this message
206            }
207            true => {
208                println!("it's accepted");
209                // Now we can execute every transitions
210                println!("transitions: {}", self.transitions.len());
211
212                for transition in self.transitions.iter_mut() {
213                    println!("transition");
214                    let _ = transition(runtime, &input, state);
215                }
216            }
217        }
218    }
219}
220
221impl<R, P, S> Service<R, P, S>
222where
223    R: Runtime + 'static,
224    P: FromRawInput + 'static,
225{
226    /// Add a guard to the service
227    ///
228    /// It acts as a service, if the function returns true the message will be processed
229    /// otherwise the message will be ignore
230    pub fn add_guard(&mut self, guard: fn(&mut R, &Input<P>) -> bool) -> &mut Self {
231        let boxed = Box::new(guard);
232        self.guards.push(boxed);
233        self
234    }
235
236    /// Add a transition to the service
237    ///
238    /// A transition can be any function of one or several parameters
239    /// The transition function should take a runtime as first parameter and then other parameters should implement FromInput
240    pub fn register<F, Marker>(&mut self, transition: F) -> &mut Self
241    where
242        F: IntoTransition<R, P, S, Marker> + 'static,
243    {
244        let fct = transition.into_transition();
245        println!("register");
246        println!("registered: {}", self.transitions.len());
247        self.transitions.push(fct);
248        self
249    }
250}
251
252pub trait IntoService<R, P, S>
253where
254    R: Runtime,
255    P: FromRawInput,
256{
257    fn into_service(self) -> Service<R, P, S>;
258}
259
260impl<R, P, S> IntoService<R, P, S> for Service<R, P, S>
261where
262    R: Runtime,
263    P: FromRawInput,
264{
265    fn into_service(self) -> Service<R, P, S> {
266        self
267    }
268}
269
270#[cfg(test)]
271mod tests {
272    use crate::core::{runtime::MockRuntime, Application, Runtime};
273
274    use super::{FromInput, IntoService, Service};
275
276    struct Test {
277        inner: String,
278    }
279
280    impl FromInput<Vec<u8>, String> for Test {
281        fn from_input<R: Runtime>(
282            _: &mut R,
283            _: &super::Input<Vec<u8>>,
284            state: &String,
285        ) -> Result<Self, ()> {
286            Ok(Self {
287                inner: state.clone(),
288            })
289        }
290    }
291
292    fn transition_0<R: Runtime>(rt: &mut R) {
293        rt.write_debug("Hello world 0");
294    }
295
296    fn transition_1<R: Runtime>(rt: &mut R, t: Test) {
297        rt.write_debug(&t.inner);
298    }
299
300    fn transition_2<R: Runtime>(rt: &mut R, _: (), _: ()) {
301        rt.write_debug("Hello world 2");
302    }
303
304    fn transition_3<R: Runtime>(rt: &mut R, _: (), _: (), _: ()) {
305        rt.write_debug("Hello world 3");
306    }
307
308    fn transition_4<R: Runtime>(rt: &mut R, _: (), _: (), _: (), _: ()) {
309        rt.write_debug("Hello world 4");
310    }
311
312    fn transition_5<R: Runtime>(rt: &mut R, _: (), _: (), _: (), _: (), _: ()) {
313        rt.write_debug("Hello world 5");
314    }
315
316    fn transition_6<R: Runtime>(rt: &mut R, _: (), _: (), _: (), _: (), _: (), _: ()) {
317        rt.write_debug("Hello world 6");
318    }
319
320    fn transition_7<R: Runtime>(rt: &mut R, _: (), _: (), _: (), _: (), _: (), _: (), _: ()) {
321        rt.write_debug("Hello world 7");
322    }
323
324    fn transition_8<R: Runtime>(
325        rt: &mut R,
326        _: (),
327        _: (),
328        _: (),
329        _: (),
330        _: (),
331        _: (),
332        _: (),
333        _: (),
334    ) {
335        rt.write_debug("Hello world 8");
336    }
337
338    fn transition_9<R: Runtime>(
339        rt: &mut R,
340        _: (),
341        _: (),
342        _: (),
343        _: (),
344        _: (),
345        _: (),
346        _: (),
347        _: (),
348        _: (),
349    ) {
350        rt.write_debug("Hello world 9");
351    }
352
353    #[test]
354    fn test() {
355        let mut runtime = MockRuntime::default();
356        runtime.add_input(Vec::default());
357        let mut service = Service::<_, Vec<u8>, String>::new("Hello world 1".to_string());
358
359        service
360            .add_guard(|_runtime, _input| true)
361            .register(transition_0)
362            .register(transition_1)
363            .register(transition_2)
364            .register(transition_3)
365            .register(transition_4)
366            .register(transition_5)
367            .register(transition_6)
368            .register(transition_7)
369            .register(transition_8)
370            .register(transition_9);
371
372        let () = Application::new(&mut runtime).service(service).run();
373
374        assert_eq!(
375            runtime.stdout(),
376            vec![
377                "Hello world 0",
378                "Hello world 1",
379                "Hello world 2",
380                "Hello world 3",
381                "Hello world 4",
382                "Hello world 5",
383                "Hello world 6",
384                "Hello world 7",
385                "Hello world 8",
386                "Hello world 9",
387            ]
388        )
389    }
390
391    struct CustomService {
392        _data: String,
393    }
394
395    fn custom_transition<R: Runtime>(_: &mut R) {}
396
397    impl<R> IntoService<R, Vec<u8>, CustomService> for CustomService
398    where
399        R: Runtime,
400    {
401        fn into_service(self) -> Service<R, Vec<u8>, Self> {
402            let mut service = Service::<R, Vec<u8>, Self>::new(self);
403            service.register(custom_transition);
404            service
405        }
406    }
407
408    #[test]
409    fn test_2() {
410        let mut runtime = MockRuntime::default();
411        let mut application = Application::new(&mut runtime);
412
413        let service = CustomService {
414            _data: "some data".to_string(),
415        };
416
417        application.service(service).run();
418    }
419}