use sfsm::*;
pub struct Launch {}
pub struct WaitForLaunch {
boosters_started: bool
}
pub struct HandleMalfunction {
res: Result<(), RocketMalfunction>,
}
impl HandleMalfunction {
pub fn new() -> Self {
Self {
res: Ok(())
}
}
}
#[derive(Debug)]
pub enum RocketMalfunction {
BoostersWontStart,
BoostersFellOff
}
impl TryState for Launch {
type Error = RocketMalfunction;
fn try_execute(&mut self) -> Result<(), Self::Error> {
Err(RocketMalfunction::BoostersFellOff) }
}
impl TryState for WaitForLaunch {
type Error = RocketMalfunction;
fn try_entry(&mut self) -> Result<(), Self::Error> {
println!("Start launch procedure");
Ok(())
}
fn try_execute(&mut self) -> Result<(), Self::Error> {
if !self.boosters_started {
Err(RocketMalfunction::BoostersWontStart) } else {
println!("Everything ok. Proceed with launch");
Ok(()) }
}
}
derive_transition_into!(WaitForLaunch, Launch);
derive_try_transition!(WaitForLaunch, Launch, TransitGuard::Transit);
impl Into<HandleMalfunction> for Launch {
fn into(self) -> HandleMalfunction {
HandleMalfunction::new()
}
}
impl Into<HandleMalfunction> for WaitForLaunch {
fn into(self) -> HandleMalfunction {
HandleMalfunction::new()
}
}
derive_try_transition!(HandleMalfunction, WaitForLaunch, TransitGuard::Transit);
impl Into<WaitForLaunch> for HandleMalfunction {
fn into(self) -> WaitForLaunch {
WaitForLaunch {
boosters_started: true
}
}
}
impl TryState for HandleMalfunction {
type Error = RocketMalfunction;
fn try_entry(&mut self) -> Result<(), Self::Error> {
if let Err(err) = &(self.res) {
match err {
RocketMalfunction::BoostersWontStart => { println!("Handle error: Turn off and restart launch");
}
RocketMalfunction::BoostersFellOff => {
println!("Handle error: Abort the launch");
return Err(RocketMalfunction::BoostersFellOff); }
}
}
Ok(())
}
}
impl TryErrorState for HandleMalfunction {
fn consume_error(&mut self, err: Self::Error) {
println!("Error state received a new error: {:?}", err);
self.res = Err(err);
}
}
add_fallible_state_machine!(
Rocket, WaitForLaunch, [WaitForLaunch, Launch, HandleMalfunction], [
WaitForLaunch => Launch, HandleMalfunction => WaitForLaunch
],
RocketMalfunction, HandleMalfunction );
#[sfsm_trace]
fn trace(log: &str) {
println!("{}", log);
}
fn run_error_example() -> Result<(), ExtendedSfsmError<RocketMalfunction>> {
let mut rocket = Rocket::new();
let wait_for_launch = WaitForLaunch {boosters_started: false};
rocket.start(wait_for_launch)?;
assert!(IsState::<WaitForLaunch>::is_state(&rocket));
rocket.step()?;
assert!(IsState::<HandleMalfunction>::is_state(&rocket));
rocket.step()?;
assert!(IsState::<WaitForLaunch>::is_state(&rocket));
rocket.step()?;
assert!(IsState::<Launch>::is_state(&rocket));
let res = rocket.step(); assert!(res.is_err());
Ok(())
}
fn main() {
run_error_example().unwrap();
}
#[cfg(test)]
mod tests {
use crate::run_error_example;
#[test]
fn fallible_example() {
run_error_example().unwrap();
}
}