Skip to content

Commit

Permalink
return error if none of the transitions failed
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmitriy Kumshayev committed Jun 5, 2024
1 parent 230b9a5 commit eaa48b5
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 20 deletions.
2 changes: 1 addition & 1 deletion examples/event_with_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn main() {
let mut sm = StateMachine::new(Context);
let result = sm.process_event(Events::Event1(MyEventData(1))); // Guard will fail

assert!(matches!(result, Err(Error::GuardFailed(()))));
assert!(matches!(result, Err(Error::TransitionsFailed)));

let result = sm.process_event(Events::Event1(MyEventData(42))); // Guard will pass

Expand Down
4 changes: 2 additions & 2 deletions examples/event_with_reference_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ fn main() {
let mut sm = StateMachine::new(Context);

let result = sm.process_event(Events::Event1(&[])); // Guard will fail
assert!(matches!(result, Err(Error::GuardFailed(()))));
assert!(matches!(result, Err(Error::TransitionsFailed)));
let result = sm.process_event(Events::Event1(&[1, 2, 3])); // Guard will pass
assert!(matches!(result, Ok(&States::State2)));

let r = 42;
let result = sm.process_event(Events::Event2(MyReferenceWrapper(&r))); // Guard will fail
assert!(matches!(result, Err(Error::GuardFailed(()))));
assert!(matches!(result, Err(Error::TransitionsFailed)));

let r = 9001;
let result = sm.process_event(Events::Event2(MyReferenceWrapper(&r))); // Guard will pass
Expand Down
2 changes: 1 addition & 1 deletion examples/ex3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ fn main() {

// The action will never run as the guard will fail
let r = sm.process_event(Events::Event2);
assert!(matches!(r, Err(Error::GuardFailed(()))));
assert!(matches!(r, Err(Error::TransitionsFailed)));

println!("After action 2");

Expand Down
2 changes: 1 addition & 1 deletion examples/guard_custom_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,5 @@ fn main() {

let r = sm.process_event(Events::Event1(MyEventData(1)));

assert!(matches!(r, Err(Error::GuardFailed(()))));
assert!(matches!(r, Err(Error::TransitionsFailed)));
}
2 changes: 1 addition & 1 deletion examples/named_ex3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ fn main() {

// The action will never run as the guard will fail
let r = sm.process_event(LoopingWithGuardsEvents::Event2);
assert!(matches!(r, Err(LoopingWithGuardsError::GuardFailed(()))));
assert!(matches!(r, Err(LoopingWithGuardsError::TransitionsFailed)));

println!("After action 2");

Expand Down
31 changes: 17 additions & 14 deletions macros/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ 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))|
if let Some(AsyncIdent {ident: g, is_async: is_g_async}) = guard {
if let Some(AsyncIdent {ident: guard_ident, is_async: is_g_async}) = guard {
let guard_await = match is_g_async {
true => { sm_is_async = true; quote! { .await } },
false => quote! { },
Expand All @@ -392,8 +392,8 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream {
false => quote! { },
};
quote! {
let guard_result = self.context.#g(#temporary_context_call #g_a_ref_param) #guard_await;
self.context.log_guard(stringify!(#g), &guard_result);
let guard_result = self.context.#guard_ident(#temporary_context_call #g_a_ref_param) #guard_await;
self.context.log_guard(stringify!(#guard_ident), &guard_result);
match guard_result {
true => {
let _data = self.context.#a(#temporary_context_call #g_a_param) #action_await;
Expand All @@ -409,8 +409,8 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream {
}
} else {
quote! {
let guard_result = self.context.#g(#temporary_context_call #g_a_ref_param);
self.context.log_guard(stringify!(#g), &guard_result);
let guard_result = self.context.#guard_ident(#temporary_context_call #g_a_ref_param);
self.context.log_guard(stringify!(#guard_ident), &guard_result);
match guard_result {
true => {
let out_state = #states_type_name::#out_state;
Expand All @@ -422,14 +422,14 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream {
}
}
}
} else if let Some(AsyncIdent {ident: a, is_async: is_a_async}) = action {
} else if let Some(AsyncIdent {ident: action_ident, is_async: is_a_async}) = action {
let action_await = match is_a_async {
true => { sm_is_async = true; quote! { .await } },
false => quote! { },
};
quote! {
let _data = self.context.#a(#temporary_context_call #g_a_param) #action_await ;
self.context.log_action(stringify!(#a));
let _data = self.context.#action_ident(#temporary_context_call #g_a_param) #action_await ;
self.context.log_action(stringify!(#action_ident));
let out_state = #states_type_name::#out_state;
self.context.log_state_change(&out_state);
self.state = Some(out_state);
Expand Down Expand Up @@ -552,11 +552,11 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream {

/// List of possible errors
#[derive(Debug)]
pub enum #error_type_name <T=()> {
pub enum #error_type_name {
/// When an event is processed which should not come in the current state.
InvalidEvent,
/// When an event is processed whose guard did not return `true`.
GuardFailed(T),
/// When an event is processed and not of the transitions happened.
TransitionsFailed,
/// When the state has an unexpected value.
///
/// This can happen if there is a bug in the code generated by smlang,
Expand Down Expand Up @@ -617,10 +617,13 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream {
#(#states_type_name::#in_states => match event {
#(#events_type_name::#events => {
#code_blocks

// all guards disabled
#[allow(unreachable_code)]
self.state()
{
// none of the guarded or non-guarded transitions occurred,
// therefore return an error,
self.state = Some(#states_type_name::#in_states);
Err(#error_type_name ::TransitionsFailed)
}
}),*
#[allow(unreachable_patterns)]
_ => {
Expand Down

0 comments on commit eaa48b5

Please sign in to comment.