use adar::prelude::*;
use std::{
fmt::Debug,
time::{Duration, Instant},
};
#[derive(Debug)]
struct Context<T>
where
T: Debug,
{
transitions: u32,
_demo: T,
}
#[StateEnum(context=for<T> Context<T> where T: Debug)]
#[derive(Debug)]
enum States {
CountState(u32),
ContinueCountState(u32),
DurationState { start: Instant },
ExitState,
}
impl<T> Machine<T> for States
where
T: Debug,
{
fn on_transition(&mut self, new_state: &Self::States, _context: &mut Self::Context) {
println!("State transition: {:?} -> {:?}", self, new_state);
}
}
impl From<&mut CountState> for ContinueCountState {
fn from(value: &mut CountState) -> Self {
Self(value.0 + 10)
}
}
impl<T> State<T> for CountState
where
T: Debug,
{
fn on_enter(&mut self, context: &mut Self::Context) {
context.transitions += 1;
println!("CountState::on_enter({:?})", context);
}
fn on_update(&mut self, context: &mut Self::Context) -> Option<Self::States> {
self.0 += 1;
println!("CountState::on_update({:?}) count={}", context, self.0);
if self.0 >= 5 {
Some(ContinueCountState::from(self).into())
} else {
None
}
}
fn on_leave(&mut self, context: &mut Self::Context) {
println!("CountState::on_leave({:?})", context);
}
}
impl<T> State<T> for ContinueCountState
where
T: Debug,
{
fn on_enter(&mut self, context: &mut Self::Context) {
context.transitions += 1;
println!("ContinueCountState::on_enter({:?})", context);
}
fn on_update(&mut self, context: &mut Self::Context) -> Option<Self::States> {
self.0 += 1;
println!(
"ContinueCountState::on_update({:?}) count={}",
context, self.0
);
if self.0 >= 20 {
Some(
DurationState {
start: Instant::now(),
}
.into(),
)
} else {
None
}
}
fn on_leave(&mut self, context: &mut Self::Context) {
println!("ContinueCountState::on_leave({:?})", context);
}
}
impl<T> State<T> for DurationState
where
T: Debug,
{
fn on_enter(&mut self, context: &mut Self::Context) {
context.transitions += 1;
println!("DurationState::on_enter({:?})", context);
}
fn on_update(&mut self, context: &mut Self::Context) -> Option<Self::States> {
let now = Instant::now();
let elapsed = now - self.start;
println!(
"DurationState::on_update({:?}) elapsed={}",
context,
elapsed.as_secs_f32()
);
if elapsed >= Duration::from_secs(3) {
Some(ExitState.into())
} else {
None
}
}
fn on_leave(&mut self, context: &mut Self::Context) {
println!("DurationState::on_leave({:?})", context);
}
}
impl<T> State<T> for ExitState
where
T: Debug,
{
fn on_enter(&mut self, context: &mut Self::Context) {
context.transitions += 1;
println!("ExitState::on_enter({:?})", context);
}
fn on_update(&mut self, context: &mut Self::Context) -> Option<Self::States> {
println!("ExitState::on_update({:?})", context);
None
}
fn on_leave(&mut self, context: &mut Self::Context) {
println!("ExitState::on_leave({:?})", context);
}
}
fn main() {
let mut sm = StateMachine::new_context(
CountState(0),
Context {
transitions: 0,
_demo: "Demo",
},
);
while !matches!(sm.state(), States::ExitState(ExitState)) {
sm.update();
std::thread::sleep(Duration::from_millis(100));
}
}