I would like to make a generic structure with closures, trying to model the finite state machine with Rust. A finite state machine holds two mappings(closures in this case);
- update: input X state => state
- output: input X state => output
Here is my first attempt.
pub struct Fsm<A, S, B, U, O>
where
A: Clone,
S: Clone,
B: Clone,
U: Fn(&A, &S) -> S + Clone,
O: Fn(&A, &S) -> B + Clone,
{
update: U,
output: O,
state: S,
_a: PhantomData<A>,
_b: PhantomData<B>,
}
impl<A, S, B, U, O> Fsm<A, S, B, U, O>
where
A: Clone,
S: Clone,
B: Clone,
U: Fn(&A, &S) -> S + Clone,
O: Fn(&A, &S) -> B + Clone,
{
pub fn new(update: U, output: O, state: S) -> Self {
Fsm {
update: update,
output: output,
state: state,
_a: PhantomData,
_b: PhantomData,
}
}
pub fn get_state(&self) -> S {
self.state.clone()
}
fn put_state(&mut self, state: &S) -> () {
self.state = state.to_owned();
}
pub fn react(&mut self, input: &A) -> B {
let new_state = (self.update)(input, &self.get_state());
self.put_state(&new_state);
(self.output)(input, &new_state)
}
}
impl<A, S1, B, U1, O1> Fsm<A, S1, B, U1, O1>
where
A: Clone,
S1: Clone,
B: Clone,
U1: Fn(&A, &S1) -> S1 + Clone,
O1: Fn(&A, &S1) -> B + Clone,
{
pub fn product<C, S2, U2, U3, O2, O3>(
self,
fsm: Fsm<B, S2, C, U2, O2>,
) -> Fsm<A, (S1, S2), C, U3, O3>
where
S2: Clone,
C: Clone,
U2: Fn(&B, &S2) -> S2 + Clone,
U3: Fn(&A, &(S1, S2)) -> (S1, S2) + Clone,
O2: Fn(&B, &S2) -> C + Clone,
O3: Fn(&A, &(S1, S2)) -> C + Clone,
{
Fsm::new(
|x, (s1, s2)| {
let new_s1 = (self.update)(x, s1);
(new_s1, (fsm.update)(&(self.output)(x, &new_s1), s2))
},
|x, (s1, s2)| {
let new_s1 = (self.update)(x, s1);
let new_s2 = (fsm.update)(&(self.output)(x, &new_s1), s2);
(fsm.output)(&(self.output)(x, &new_s1), &new_s2)
},
(self.state, fsm.state),
)
}
}
However, it has two annoying parts;
- If one does not put
_a
, and_b
compiler complains.A, B
are there to relate theU
andO
. - the product part make compile error like following;
arguments to this function are incorrect
expected type parameter `U3`
found closure `[closure@src/lib.rs:104:13: 104:26]`
every closure has a distinct type and so could not always match the caller-chosen type of parameter `U3`
expected type parameter `O3`
found closure `[closure@src/lib.rs:108:13: 108:26]`
every closure has a distinct type and so could not always match the caller-chosen type of parameter `O3`rustcClick for full compiler diagnostic
How could I resolve these issues?