Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added transition_callback #77

Merged
merged 2 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Added

- Add transition callback. A function which is called for every transition. It has default empty
implementation.

## [0.7.0] - 2024-07-03

### Added
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,12 @@ The statemachine will create for all states an `on_entry_` and `on_exit_` functi
If the are not used, they will be optimized away by the compiler. An example be
found in `on_entry_on_exit_generic`.

### Transition callback

The statemachine will call for every transition a transition callback. This function
is called with both the old state and new state as arguments. An example can be found
in `dominos`.

## Helpers

### Auto-derive certain traits for states and events
Expand Down
5 changes: 5 additions & 0 deletions examples/dominos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use smlang::statemachine;

statemachine! {
derive_states: [Debug],
derive_events: [Debug],
transitions: {
*D0 + ToD1 / to_d2 = D1,
D1(Option<Events>) + ToD2 / to_d3 = D2,
Expand Down Expand Up @@ -33,6 +35,9 @@ impl StateMachineContext for Context {
fn to_d5(&mut self, _state_data: &Option<Events>) -> Result<Option<Events>, ()> {
Ok(Some(Events::ToD5))
}
fn transition_callback(&self, exit: &States, entry: &States) {
println!("Domino {:?} fell. Next up: {:?}", exit, entry);
}
}

// The macros does not derive Copy/Clone traits to the events, so we need to add them so that the
Expand Down
10 changes: 7 additions & 3 deletions macros/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,6 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream {
let streams: Vec<TokenStream> =
guard.iter()
.zip(action.iter().zip(out_state)).map(|(guard, (action,out_state))| {

let binding = out_state.to_string();
let out_state_string = &binding.split('(').next().unwrap();
let binding = in_state.to_string();
Expand Down Expand Up @@ -441,7 +440,6 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream {
self.context.#guard_ident(#temporary_context_call #guard_params) #guard_await .map_err(#error_type_name::GuardFailed)?
}
});

quote! {
// This #guard_expression contains a boolean expression of guard functions
// Each guard function has Result<bool,_> return type.
Expand All @@ -458,17 +456,18 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream {
let out_state = #states_type_name::#out_state;
self.context.log_state_change(&out_state);
#entry_exit_states
self.context().transition_callback(&self.state, &out_state);
self.state = out_state;
return Ok(&self.state);
}
}
} else { // Unguarded transition

quote!{
#action_code
let out_state = #states_type_name::#out_state;
self.context.log_state_change(&out_state);
#entry_exit_states
self.context().transition_callback(&self.state, &out_state);
self.state = out_state;
return Ok(&self.state);
}
Expand Down Expand Up @@ -569,6 +568,11 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream {
/// `process_event()`. No-op by default but can be overridden in implementations
/// of a state machine's `StateMachineContext` trait.
fn log_state_change(&self, new_state: & #states_type_name) {}

/// Called when transitioning to a new state as a result of an event passed to
/// `process_event()`. No-op by default which can be overridden in implementations
/// of a state machine's `StateMachineContext` trait.
fn transition_callback(&self, old_state: & #states_type_name, new_state: & #states_type_name) {}
}

/// List of auto-generated states.
Expand Down