1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
use fsm::{Fsm, StateFn, FsmTypes};
use constraints::Constraints;

pub struct Checker<T: FsmTypes> {
    pub fsm: Fsm<T>,
    constraints: Constraints<T>
}

impl<T: FsmTypes> Checker<T> {
    pub fn new(ctx: T::Context, state: StateFn<T>, constraints: Constraints<T>) -> Checker<T> {
        Checker {
            fsm: Fsm::<T>::new(ctx, state),
            constraints: constraints
        }
    }

    pub fn check(&mut self, msg: T::Msg) -> Result<Vec<T::Output>, String> {
        let (from, init_ctx) = try!(self.check_preconditions());
        let output = self.fsm.send(msg.clone());
        self.check_postconditions(from, &init_ctx, &msg, &output).map(|_| output)
    }

    pub fn check_preconditions(&self) -> Result<(&'static str, T::Context), String> {
        let (from, ctx) = self.fsm.get_state();
        try!(self.constraints.check_preconditions(from, &ctx));
        try!(self.constraints.check_invariants(&ctx));
        Ok((from, ctx.clone()))
    }

    pub fn check_postconditions(&self,
                                from: &'static str,
                                init_ctx: &T::Context,
                                msg: &T::Msg,
                                output: &Vec<T::Output>) -> Result<(), String> {
        let (to, final_ctx) = self.fsm.get_state();
        try!(self.constraints.check_invariants(&final_ctx));
        self.constraints.check_transition(from, to, init_ctx, final_ctx, msg, output)
    }
}