use crate::machine::{EventKind, StateMachine};
use core::marker::PhantomData;
type Check<S, E> = Box<dyn Fn(&S, &E, &Option<S>) -> bool>;
pub struct Invariant<S, E> {
description: &'static str,
check: Check<S, E>,
}
impl<S, E> Invariant<S, E> {
pub fn custom(description: &'static str) -> PartialInvariant<S, E> {
PartialInvariant {
description,
_marker: PhantomData,
}
}
pub fn description(&self) -> &'static str {
self.description
}
pub fn holds(&self, before: &S, event: &E, after: &Option<S>) -> bool {
(self.check)(before, event, after)
}
}
pub struct PartialInvariant<S, E> {
description: &'static str,
_marker: PhantomData<fn(&S, &E)>,
}
impl<S, E> PartialInvariant<S, E> {
pub fn assert(self, check: impl Fn(&S, &E, &Option<S>) -> bool + 'static) -> Invariant<S, E> {
Invariant {
description: self.description,
check: Box::new(check),
}
}
}
pub trait Invariants: StateMachine
where
Self::Event: EventKind,
{
fn invariants() -> Vec<Invariant<Self, Self::Event>>;
}