use adar::{async_trait, prelude::*};
use std::{process::Command, time::Duration};
use tokio::{main, time::sleep};
#[StateEnumAsync]
#[ReflectEnum] enum TrafficLight {
Go,
GetReady,
StopIfSafe,
Stop,
}
impl TrafficLight {
const YELLOW_DURATION: Duration = Duration::from_secs(1);
const GO_STOP_DURATION: Duration = Duration::from_secs(2);
}
#[cfg_attr(feature="async-st", async_trait(?Send))]
#[cfg_attr(not(feature = "async-st"), async_trait)]
impl MachineAsync for TrafficLight {
async fn on_transition(&mut self, new_state: &Self::States, _context: &mut Self::Context) {
Command::new("clear")
.status()
.expect("Failed to clear the screen!");
println!("{}", new_state.name());
}
}
#[cfg_attr(feature="async-st", async_trait(?Send))]
#[cfg_attr(not(feature = "async-st"), async_trait)]
impl StateAsync for Go {
async fn on_enter(&mut self, _context: &mut Self::Context) {
println!("⚫\n⚫\n🟢");
}
async fn on_update(&mut self, _context: &mut Self::Context) -> Option<Self::States> {
std::thread::sleep(TrafficLight::GO_STOP_DURATION);
Some(StopIfSafe.into())
}
}
#[cfg_attr(feature="async-st", async_trait(?Send))]
#[cfg_attr(not(feature = "async-st"), async_trait)]
impl StateAsync for GetReady {
async fn on_enter(&mut self, _context: &mut Self::Context) {
println!("🔴\n🟡\n⚫");
}
async fn on_update(&mut self, _context: &mut Self::Context) -> Option<Self::States> {
sleep(TrafficLight::YELLOW_DURATION).await;
Some(Go.into())
}
}
#[cfg_attr(feature="async-st", async_trait(?Send))]
#[cfg_attr(not(feature = "async-st"), async_trait)]
impl StateAsync for StopIfSafe {
async fn on_enter(&mut self, _context: &mut Self::Context) {
println!("⚫\n🟡\n⚫");
}
async fn on_update(&mut self, _context: &mut Self::Context) -> Option<Self::States> {
sleep(TrafficLight::YELLOW_DURATION).await;
Some(Stop.into())
}
}
#[cfg_attr(feature="async-st", async_trait(?Send))]
#[cfg_attr(not(feature = "async-st"), async_trait)]
impl StateAsync for Stop {
async fn on_enter(&mut self, _context: &mut Self::Context) {
println!("🔴\n⚫\n⚫")
}
async fn on_update(&mut self, _context: &mut Self::Context) -> Option<Self::States> {
sleep(TrafficLight::GO_STOP_DURATION).await;
Some(GetReady.into())
}
}
#[cfg_attr(feature = "async-st", main(flavor = "current_thread"))]
#[cfg_attr(not(feature = "async-st"), main(flavor = "multi_thread"))]
async fn main() {
StateMachineAsync::new(Stop).await.run().await;
}