funcan_rs/machine.rs
1//! # Machine Module
2//!
3//! This module offers traits for working with abstract finite state machines.
4
5/// A trait that represents a finite state machine (FSM).
6///
7/// # Type Parameters
8///
9/// - `X`: The type of the input or event that causes state transitions.
10///
11/// # Associated Types
12///
13/// - `Observation`: The type that represents abstract observations of machine states or outputs.
14pub trait MachineTrans<X> {
15 /// An associated type for capturing the machine's state or output observations.
16 type Observation;
17
18 /// Transitions the state machine to a new state based on the input.
19 ///
20 /// This method modifies the machine's current state according to
21 /// the specified input `x`. The exact details of the transition
22 /// mechanism are determined by the implementer.
23 ///
24 /// # Parameters
25 ///
26 /// - `x`: An input value of type `X` that influences the state change.
27 fn transit(self: &mut Self, x: X);
28
29 /// Makes an observation of the machine's current state.
30 ///
31 /// This method returns an abstract representation of the state or output
32 /// of the machine as defined by the `Observation` associated type.
33 fn observe(self: &Self) -> Self::Observation;
34
35 /// Resets the machine's state to its initial state.
36 ///
37 /// This method should bring the machine back to its starting condition.
38 fn initial(self: &mut Self);
39}
40
41/// A trait for machines that have some final states and an associated value.
42///
43/// This is useful for cases where a machine can complete its execution
44/// and produce a final value outcome.
45pub trait Final {
46 /// An associated type representing the value corresponding to a final state.
47 type FinalValue;
48
49 /// Determines if the current state is a final state.
50 ///
51 /// # Returns
52 ///
53 /// - `None` if not in a final state.
54 /// - `Some(val)` with `val` of type `FinalValue` if in a final state.
55 fn is_final(self: Self) -> Option<Self::FinalValue>;
56}
57
58/// Represents the composition of two finite state machines,
59/// where the output of the first machine (`M0`) serves as the input to the second machine (`M1`).
60pub struct Comp<M0, M1> {
61 /// The first state machine.
62 pub m0: M0,
63 /// The second state machine.
64 pub m1: M1,
65}
66
67/// Implementation of the `MachineTrans` trait for the composition of two finite state machines, `M0` and `M1`.
68///
69/// This is applicable when the final values of machine `M0` can be used as inputs to machine `M1`.
70///
71/// A common use case is where `M0` processes and decodes some low-level input
72/// to generate higher-level inputs for machine `M1`.
73impl<X, M0, M1> MachineTrans<X> for Comp<M0, M1>
74where
75 M0: MachineTrans<X>,
76 <M0 as MachineTrans<X>>::Observation: Final,
77 M1: MachineTrans<<<M0 as MachineTrans<X>>::Observation as Final>::FinalValue>,
78{
79 /// Observable values of the composed machines derived from `M1`.
80 type Observation = <M1 as MachineTrans<
81 <<M0 as MachineTrans<X>>::Observation as Final>::FinalValue,
82 >>::Observation;
83
84 /// Processes an input `x` by passing it through machine `M0`.
85 ///
86 /// If `M0` reaches a final state, its output is utilized as input for machine `M1`.
87 fn transit(self: &mut Self, x: X) {
88 self.m0.transit(x);
89 if let Some(y) = self.m0.observe().is_final() {
90 // Reset `m0` to initial state
91 self.m0.initial();
92 // Transition `m1` with the final state's value of `m0`
93 self.m1.transit(y);
94 }
95 }
96
97 /// Observes and returns the current state of the composed machine.
98 ///
99 /// The observation is based on `M1`.
100 fn observe(self: &Self) -> Self::Observation {
101 self.m1.observe()
102 }
103
104 /// Resets both `M0` and `M1` to their initial states.
105 ///
106 /// Ensures that the entire composite machine starts at its initial configuration.
107 fn initial(self: &mut Self) {
108 self.m0.initial();
109 self.m1.initial();
110 }
111}