Skip to content

Commit

Permalink
Added generic on_entry_on_exit flag
Browse files Browse the repository at this point in the history
Signed-off-by: Martin Broers <[email protected]>
  • Loading branch information
Martin Broers committed Jun 27, 2024
1 parent 2785f10 commit a127650
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 32 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,11 @@ function.

An example is available in `on_entry_on_exit`.

There is also a generic flag available, `generate_on_entry_on_exit`, which will
generate for all states in the statemachine an entry and an exit function. If
they are not used, they will be optimized away by the compiler. An example be
found in `on_entry_on_exit_generic`.

## Helpers

### Auto-derive certain traits for states and events
Expand Down
70 changes: 70 additions & 0 deletions examples/on_entry_on_exit_generic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//! An example of using state data to propagate events (See issue-17)

#![deny(missing_docs)]

use smlang::statemachine;

statemachine! {
name: OnEntryExample,
generate_entry_exit_states: true,
transitions: {
*D0 < exit_d0 + ToD1 = D1,
D0 + ToD3 = D3,
D1 + ToD2 = D2,
D2 + ToD1 = D1,
D1 + ToD0 = D0,
},
}

/// Context
pub struct Context {
exited_d0: i32,
entered_d1: i32,
}

impl OnEntryExampleStateMachineContext for Context {
fn on_exit_d0(&mut self) {
self.exited_d0 += 1;
}
fn on_entry_d1(&mut self) {
self.entered_d1 += 1;
}
}

fn main() {
let mut sm = OnEntryExampleStateMachine::new(Context {
exited_d0: 0,
entered_d1: 0,
});

// first event starts the dominos
let _ = sm.process_event(OnEntryExampleEvents::ToD1).unwrap();

assert!(matches!(sm.state(), Ok(&OnEntryExampleStates::D1)));
assert_eq!(sm.context().exited_d0, 1);
assert_eq!(sm.context().entered_d1, 1);

let _ = sm.process_event(OnEntryExampleEvents::ToD2).unwrap();

assert!(matches!(sm.state(), Ok(&OnEntryExampleStates::D2)));
assert_eq!(sm.context().exited_d0, 1);
assert_eq!(sm.context().entered_d1, 1);

let _ = sm.process_event(OnEntryExampleEvents::ToD1).unwrap();

assert!(matches!(sm.state(), Ok(&OnEntryExampleStates::D1)));
assert_eq!(sm.context().exited_d0, 1);
assert_eq!(sm.context().entered_d1, 2);

let _ = sm.process_event(OnEntryExampleEvents::ToD0).unwrap();

assert!(matches!(sm.state(), Ok(&OnEntryExampleStates::D0)));
assert_eq!(sm.context().exited_d0, 1);
assert_eq!(sm.context().entered_d1, 2);

let _ = sm.process_event(OnEntryExampleEvents::ToD3).unwrap();

assert!(matches!(sm.state(), Ok(&OnEntryExampleStates::D3)));
assert_eq!(sm.context().exited_d0, 2);
assert_eq!(sm.context().entered_d1, 2);
}
13 changes: 6 additions & 7 deletions macros/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream {
let generate_entry_exit_states = sm.generate_entry_exit_states;
let generate_transition_callback = sm.generate_transition_callback;

let entry_fns = &sm.entry_functions;
let exit_fns = &sm.exit_functions;
let mut entry_fns = sm.entry_functions.clone();
let mut exit_fns = sm.exit_functions.clone();

// Get only the unique states
let mut state_list: Vec<_> = sm.states.values().collect();
Expand Down Expand Up @@ -254,8 +254,6 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream {
let mut guard_list = proc_macro2::TokenStream::new();
let mut action_list = proc_macro2::TokenStream::new();

let mut entry_list = proc_macro2::TokenStream::new();

let mut entries_exits = proc_macro2::TokenStream::new();
for ident in entry_fns.values() {
entries_exits.extend(quote! {
Expand All @@ -279,15 +277,17 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream {
};
if generate_entry_exit_states {
let entry_ident = format_ident!("on_entry_{}", string_morph::to_snake_case(state));
entry_list.extend(quote! {
entries_exits.extend(quote! {
#[allow(missing_docs)]
fn #entry_ident(&mut self){}
});
entry_fns.insert(format_ident!("{}", state), entry_ident);
let exit_ident = format_ident!("on_exit_{}", string_morph::to_snake_case(state));
entry_list.extend(quote! {
entries_exits.extend(quote! {
#[allow(missing_docs)]
fn #exit_ident(&mut self){}
});
exit_fns.insert(format_ident!("{}", state), exit_ident);
};

for (event, event_mapping) in event_mappings {
Expand Down Expand Up @@ -616,7 +616,6 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream {
#guard_error
#guard_list
#action_list
#entry_list
#entries_exits


Expand Down
3 changes: 0 additions & 3 deletions macros/src/parser/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ pub struct Transition {
pub guard: Option<GuardExpression>,
pub action: Option<AsyncIdent>,
pub out_state: Ident,

pub entry_fn: Option<Ident>,
pub exit_fn: Option<Ident>,
}

impl parse::Parse for Event {
Expand Down
23 changes: 1 addition & 22 deletions macros/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,11 @@ fn add_transition(
transition: &StateTransition,
transition_map: &mut TransitionMap,
state_data: &DataDefinitions,
entry_fns: &HashMap<Ident, Ident>,
exit_fns: &HashMap<Ident, Ident>,
) -> Result<(), parse::Error> {
let p = transition_map
.get_mut(&transition.in_state.ident.to_string())
.unwrap();

let entry_fn = entry_fns.get(&transition.in_state.ident.clone());
let exit_fn = exit_fns.get(&transition.in_state.ident.clone());

match p.entry(transition.event.ident.to_string()) {
hash_map::Entry::Vacant(entry) => {
let mapping = EventMapping {
Expand All @@ -94,8 +89,6 @@ fn add_transition(
guard: transition.guard.clone(),
action: transition.action.clone(),
out_state: transition.out_state.ident.clone(),
entry_fn: entry_fn.cloned(),
exit_fn: exit_fn.cloned(),
}],
};
entry.insert(mapping);
Expand All @@ -106,8 +99,6 @@ fn add_transition(
guard: transition.guard.clone(),
action: transition.action.clone(),
out_state: transition.out_state.ident.clone(),
entry_fn: entry_fn.cloned(),
exit_fn: exit_fn.cloned(),
});
}
}
Expand Down Expand Up @@ -166,10 +157,6 @@ impl ParsedStateMachine {
map.insert(input_state.ident.clone(), identifier.ident.clone())
{
if identifier.ident != existing_identifier {
println!(
"entry_state: {:?}, state.ident: {:?}",
identifier.ident, input_state.ident
);
return Err(parse::Error::new(
Span::call_site(),
"Different entry or exit functions defined for state",
Expand Down Expand Up @@ -248,8 +235,6 @@ impl ParsedStateMachine {
&wildcard_transition,
&mut states_events_mapping,
&state_data,
&states_with_entry_function,
&states_with_exit_function,
)?;

transition_added = true;
Expand All @@ -264,13 +249,7 @@ impl ParsedStateMachine {
));
}
} else {
add_transition(
transition,
&mut states_events_mapping,
&state_data,
&states_with_entry_function,
&states_with_exit_function,
)?;
add_transition(transition, &mut states_events_mapping, &state_data)?;
}
}

Expand Down

0 comments on commit a127650

Please sign in to comment.