Skip to content

Commit

Permalink
Add After dispatch hook and Before transition, rename existing hooks (#…
Browse files Browse the repository at this point in the history
…23)

* add after_dispatch hook

* rename on_dispatch to before_dispatch

* rename on_transition to after_transition

* add before_transition callback

* make all callbacks uppercase

* add missing call to M::BEFORE_TRANSITION

* Update examples/macro/async_blinky/src/main.rs

Co-authored-by: Maxim Deloof <[email protected]>

* Update examples/macro/async_blinky/src/main.rs

Co-authored-by: Maxim Deloof <[email protected]>

* Update examples/macro/async_blinky/src/main.rs

Co-authored-by: Maxim Deloof <[email protected]>

* missing before_transition in docs

* docs update for before_transition

* bump version

* docs update for before_transition

* fix statig_macro version in statig

* fix example in README

---------

Co-authored-by: Maxim Deloof <[email protected]>
  • Loading branch information
dragonnn and mdeloof authored Jan 8, 2025
1 parent 3014f00 commit bbda6fe
Show file tree
Hide file tree
Showing 18 changed files with 225 additions and 89 deletions.
28 changes: 20 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,14 +250,18 @@ state_machine.handle_with_context(&Event::TimerElapsed, &mut context);

For logging purposes you can define two callbacks that will be called at specific points during state machine execution.

- `on_dispatch` is called before an event is dispatched to a specific state or superstate.
- `on_transition` is called after a transition has occured.
- `before_dispatch` is called before an event is dispatched to a specific state or superstate.
- `after_dispatch` is called after an event is dispatched to a specific state or superstate.
- `before_transition` is called before a transition has occured.
- `after_transition` is called after a transition has occured.

```rust
#[state_machine(
initial = "State::on()",
on_dispatch = "Self::on_dispatch",
on_transition = "Self::on_transition",
before_dispatch = "Self::before_dispatch",
after_dispatch = "Self::after_dispatch",
before_transition = "Self::before_transition",
after_transition = "Self::after_transition",
state(derive(Debug)),
superstate(derive(Debug))
)]
Expand All @@ -266,12 +270,20 @@ impl Blinky {
}

impl Blinky {
fn on_transition(&mut self, source: &State, target: &State) {
println!("transitioned from `{:?}` to `{:?}`", source, target);
fn before_dispatch(&mut self, state: StateOrSuperstate<Blinky>, event: &Event) {
println!("before dispatched `{:?}` to `{:?}`", event, state);
}

fn on_dispatch(&mut self, state: StateOrSuperstate<Blinky>, event: &Event) {
println!("dispatched `{:?}` to `{:?}`", event, state);
fn after_dispatch(&mut self, state: StateOrSuperstate<Blinky>, event: &Event) {
println!("after dispatched `{:?}` to `{:?}`", event, state);
}

fn before_transition(&mut self, source: &State, target: &State) {
println!("before transitioned from `{:?}` to `{:?}`", source, target);
}

fn after_transition(&mut self, source: &State, target: &State) {
println!("after transitioned from `{:?}` to `{:?}`", source, target);
}
}
```
Expand Down
30 changes: 21 additions & 9 deletions examples/macro/async_blinky/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,14 @@ pub enum Event {
state(derive(Debug)),
// Derive the Debug trait on the `Superstate` enum.
superstate(derive(Debug)),
// Set the `on_transition` callback.
on_transition = "Self::on_transition",
// Set the `on_dispatch` callback.
on_dispatch = "Self::on_dispatch"
// Set the `after_transition` callback.
after_transition = "Self::after_transition",
// Set the `before_dispatch` callback.
before_dispatch = "Self::before_dispatch",
// Set the `after_dispatch` callback.
after_dispatch = "Self::after_dispatch",
// Set the `before_transition` callback.
before_transition = "Self::before_transition"
)]
impl Blinky {
#[action]
Expand Down Expand Up @@ -78,13 +82,21 @@ impl Blinky {
}

impl Blinky {
// The `on_transition` callback that will be called after every transition.
fn on_transition(&mut self, source: &State, target: &State) {
println!("transitioned from `{source:?}` to `{target:?}`");
// The `after_transition` callback that will be called after every transition.
fn after_transition(&mut self, source: &State, target: &State) {
println!("after transitioned from `{source:?}` to `{target:?}`");
}

fn on_dispatch(&mut self, state: StateOrSuperstate<Self>, event: &Event) {
println!("dispatching `{event:?}` to `{state:?}`");
fn before_transition(&mut self, source: &State, target: &State) {
println!("before transitioned from `{source:?}` to `{target:?}`");
}

fn before_dispatch(&mut self, state: StateOrSuperstate<Self>, event: &Event) {
println!("before dispatching `{event:?}` to `{state:?}`");
}

fn after_dispatch(&mut self, state: StateOrSuperstate<Self>, event: &Event) {
println!("after dispatched `{event:?}` to `{state:?}`");
}
}

Expand Down
14 changes: 7 additions & 7 deletions examples/macro/blinky/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ pub enum Event {
state(derive(Debug)),
// Derive the Debug trait on the `Superstate` enum.
superstate(derive(Debug)),
// Set the `on_transition` callback.
on_transition = "Self::on_transition",
// Set the `on_dispatch` callback.
on_dispatch = "Self::on_dispatch"
// Set the `after_transition` callback.
after_transition = "Self::after_transition",
// Set the `before_dispatch` callback.
before_dispatch = "Self::before_dispatch"
)]
impl Blinky {
/// The `#[state]` attibute marks this as a state handler. By default the
Expand Down Expand Up @@ -73,12 +73,12 @@ impl Blinky {
}

impl Blinky {
// The `on_transition` callback that will be called after every transition.
fn on_transition(&mut self, source: &State, target: &State) {
// The `after_transition` callback that will be called after every transition.
fn after_transition(&mut self, source: &State, target: &State) {
println!("transitioned from `{source:?}` to `{target:?}`");
}

fn on_dispatch(&mut self, state: StateOrSuperstate<Self>, event: &Event) {
fn before_dispatch(&mut self, state: StateOrSuperstate<Self>, event: &Event) {
println!("dispatching `{event:?}` to `{state:?}`");
}
}
Expand Down
4 changes: 2 additions & 2 deletions examples/macro/history/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ pub struct Dishwasher {

#[state_machine(
initial = "State::idle()",
on_transition = "Self::on_transition",
after_transition = "Self::after_transition",
state(derive(Debug, Clone))
)]
impl Dishwasher {
// On every transition we update the previous state, so we can transition back to it.
fn on_transition(&mut self, source: &State, _target: &State) {
fn after_transition(&mut self, source: &State, _target: &State) {
// println!("transitioned from `{:?}` to `{:?}`", source, _target);
self.previous_state = source.clone();
}
Expand Down
2 changes: 1 addition & 1 deletion examples/no_macro/basic/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl IntoStateMachine for Blinky {
const INITIAL: State = State::Off;

/// This method is called on every transition of the state machine.
const ON_TRANSITION: fn(&mut Self, &Self::State, &Self::State) = |_, source, target| {
const AFTER_TRANSITION: fn(&mut Self, &Self::State, &Self::State) = |_, source, target| {
println!("transitioned from {source:?} to {target:?}");
};
}
Expand Down
2 changes: 1 addition & 1 deletion examples/no_macro/history/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl IntoStateMachine for Dishwasher {

// On every transition we update the previous state, so we can
// transition back to it.
const ON_TRANSITION: fn(&mut Self, &Self::State, &Self::State) = |shared, source, target| {
const AFTER_TRANSITION: fn(&mut Self, &Self::State, &Self::State) = |shared, source, target| {
shared.previous_state = source.clone();
};
}
Expand Down
2 changes: 1 addition & 1 deletion macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "statig_macro"
version = "0.3.0"
version = "0.4.0"
edition = "2021"
rust-version = "1.66"
authors = ["Maxim Deloof"]
Expand Down
60 changes: 44 additions & 16 deletions macro/src/analyze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,14 @@ pub struct StateMachine {
pub context_ident: Ident,
/// The visibility of the derived types.
pub visibility: Visibility,
/// Optional `on_transition` callback.
pub on_transition: Option<Path>,
/// Optional `on_dispatch` callback.
pub on_dispatch: Option<Path>,
/// Optional `before_transition` callback.
pub before_transition: Option<Path>,
/// Optional `after_transition` callback.
pub after_transition: Option<Path>,
/// Optional `before_dispatch` callback.
pub before_dispatch: Option<Path>,
/// Optional `after_dispatch` callback.
pub after_dispatch: Option<Path>,
}

/// Information regarding a state.
Expand Down Expand Up @@ -179,8 +183,10 @@ pub fn analyze_state_machine(attribute_args: &AttributeArgs, item_impl: &ItemImp
let mut superstate_ident = parse_quote!(Superstate);
let mut superstate_derives = Vec::new();

let mut on_transition = None;
let mut on_dispatch = None;
let mut after_transition = None;
let mut before_transition = None;
let mut before_dispatch = None;
let mut after_dispatch = None;

let mut visibility = parse_quote!(pub);
let mut event_ident = parse_quote!(event);
Expand Down Expand Up @@ -217,17 +223,33 @@ pub fn analyze_state_machine(attribute_args: &AttributeArgs, item_impl: &ItemImp
}
}
NestedMeta::Meta(Meta::NameValue(name_value))
if name_value.path.is_ident("on_transition") =>
if name_value.path.is_ident("before_transition") =>
{
on_transition = match &name_value.lit {
before_transition = match &name_value.lit {
Lit::Str(input_pat) => Some(input_pat.parse().unwrap()),
_ => abort!(name_value, "must be a string literal"),
}
}
NestedMeta::Meta(Meta::NameValue(name_value))
if name_value.path.is_ident("on_dispatch") =>
if name_value.path.is_ident("after_transition") =>
{
on_dispatch = match &name_value.lit {
after_transition = match &name_value.lit {
Lit::Str(input_pat) => Some(input_pat.parse().unwrap()),
_ => abort!(name_value, "must be a string literal"),
}
}
NestedMeta::Meta(Meta::NameValue(name_value))
if name_value.path.is_ident("before_dispatch") =>
{
before_dispatch = match &name_value.lit {
Lit::Str(input_pat) => Some(input_pat.parse().unwrap()),
_ => abort!(name_value, "must be a string literal"),
}
}
NestedMeta::Meta(Meta::NameValue(name_value))
if name_value.path.is_ident("after_dispatch") =>
{
after_dispatch = match &name_value.lit {
Lit::Str(input_pat) => Some(input_pat.parse().unwrap()),
_ => abort!(name_value, "must be a string literal"),
}
Expand Down Expand Up @@ -339,8 +361,10 @@ pub fn analyze_state_machine(attribute_args: &AttributeArgs, item_impl: &ItemImp
state_derives,
superstate_ident,
superstate_derives,
on_dispatch,
on_transition,
before_dispatch,
after_dispatch,
before_transition,
after_transition,
event_ident,
context_ident,
visibility,
Expand Down Expand Up @@ -644,8 +668,10 @@ fn valid_state_analyze() {
let state_derives = vec![parse_quote!(Copy), parse_quote!(Clone)];
let superstate_ident = parse_quote!(Superstate);
let superstate_derives = vec![parse_quote!(Copy), parse_quote!(Clone)];
let on_transition = None;
let on_dispatch = None;
let before_transition = None;
let after_transition = None;
let before_dispatch = None;
let after_dispatch = None;
let event_ident = parse_quote!(event);
let context_ident = parse_quote!(context);
let visibility = parse_quote!(pub);
Expand All @@ -659,8 +685,10 @@ fn valid_state_analyze() {
state_derives,
superstate_ident,
superstate_derives,
on_transition,
on_dispatch,
before_transition,
after_transition,
before_dispatch,
after_dispatch,
event_ident,
context_ident,
visibility,
Expand Down
31 changes: 23 additions & 8 deletions macro/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,30 @@ fn codegen_state_machine_impl(ir: &Ir) -> ItemImpl {
Mode::Awaitable => quote!(awaitable),
};

let on_transition = match &ir.state_machine.on_transition {
let before_transition = match &ir.state_machine.before_transition {
None => quote!(),
Some(on_transition) => quote!(
const ON_TRANSITION: fn(&mut Self, &Self::State, &Self::State) = #on_transition;
Some(before_transition) => quote!(
const BEFORE_TRANSITION: fn(&mut Self, &Self::State, &Self::State) = #before_transition;
),
};

let on_dispatch = match &ir.state_machine.on_dispatch {
let after_transition = match &ir.state_machine.after_transition {
None => quote!(),
Some(on_dispatch) => quote!(
const ON_DISPATCH: fn(&mut Self, StateOrSuperstate<'_, '_, Self>, &Self::Event<'_>) = #on_dispatch;
Some(after_transition) => quote!(
const AFTER_TRANSITION: fn(&mut Self, &Self::State, &Self::State) = #after_transition;
),
};

let before_dispatch = match &ir.state_machine.before_dispatch {
None => quote!(),
Some(before_dispatch) => quote!(
const BEFORE_DISPATCH: fn(&mut Self, StateOrSuperstate<'_, '_, Self>, &Self::Event<'_>) = #before_dispatch;
),
};
let after_dispatch = match &ir.state_machine.after_dispatch {
None => quote!(),
Some(after_dispatch) => quote!(
const AFTER_DISPATCH: fn(&mut Self, StateOrSuperstate<'_, '_, Self>, &Self::Event<'_>) = #after_dispatch;
),
};

Expand All @@ -82,9 +95,11 @@ fn codegen_state_machine_impl(ir: &Ir) -> ItemImpl {
type Superstate<#superstate_lifetime> = #superstate_ident #superstate_generics ;
const INITIAL: #state_ident #state_generics = #initial_state;

#on_transition
#before_transition
#after_transition

#on_dispatch
#before_dispatch
#after_dispatch
}
)
}
Expand Down
36 changes: 24 additions & 12 deletions macro/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,14 @@ pub struct StateMachine {
pub superstate_derives: Vec<Path>,
/// The generics associated with the superstate type.
pub superstate_generics: Generics,
/// The path of the `on_transition` callback.
pub on_transition: Option<Path>,
/// The path of the `on_dispatch` callback.
pub on_dispatch: Option<Path>,
/// The path of the `before_transition` callback.
pub before_transition: Option<Path>,
/// The path of the `after_transition` callback.
pub after_transition: Option<Path>,
/// The path of the `before_dispatch` callback.
pub before_dispatch: Option<Path>,
/// The path of the `after_dispatch` callback.
pub after_dispatch: Option<Path>,
/// The visibility for the derived types,
pub visibility: Visibility,
/// The external input pattern.
Expand Down Expand Up @@ -136,8 +140,10 @@ pub fn lower(model: &Model) -> Ir {
let initial_state = model.state_machine.initial_state.clone();
let state_ident = model.state_machine.state_ident.clone();
let superstate_ident = model.state_machine.superstate_ident.clone();
let on_transition = model.state_machine.on_transition.clone();
let on_dispatch = model.state_machine.on_dispatch.clone();
let before_transition = model.state_machine.before_transition.clone();
let after_transition = model.state_machine.after_transition.clone();
let before_dispatch = model.state_machine.before_dispatch.clone();
let after_dispatch = model.state_machine.after_dispatch.clone();
let event_ident = model.state_machine.event_ident.clone();
let context_ident = model.state_machine.context_ident.clone();
let shared_storage_type = model.state_machine.shared_storage_type.clone();
Expand Down Expand Up @@ -420,8 +426,10 @@ pub fn lower(model: &Model) -> Ir {
superstate_ident,
superstate_derives,
superstate_generics,
on_transition,
on_dispatch,
before_transition,
after_transition,
before_dispatch,
after_dispatch,
visibility,
event_ident,
context_ident,
Expand Down Expand Up @@ -707,8 +715,10 @@ fn create_analyze_state_machine() -> analyze::StateMachine {
state_derives: vec![parse_quote!(Copy), parse_quote!(Clone)],
superstate_ident: parse_quote!(Superstate),
superstate_derives: vec![parse_quote!(Copy), parse_quote!(Clone)],
on_transition: None,
on_dispatch: None,
before_transition: None,
after_transition: None,
before_dispatch: None,
after_dispatch: None,
visibility: parse_quote!(pub),
event_ident: parse_quote!(input),
context_ident: parse_quote!(context),
Expand All @@ -732,8 +742,10 @@ fn create_lower_state_machine() -> StateMachine {
superstate_ident: parse_quote!(Superstate),
superstate_derives: vec![parse_quote!(Copy), parse_quote!(Clone)],
superstate_generics,
on_transition: None,
on_dispatch: None,
before_transition: None,
after_transition: None,
before_dispatch: None,
after_dispatch: None,
visibility: parse_quote!(pub),
event_ident: parse_quote!(input),
context_ident: parse_quote!(context),
Expand Down
Loading

0 comments on commit bbda6fe

Please sign in to comment.