From 8bd2571d2472dfac89c02c9053dd0c07d9cfba44 Mon Sep 17 00:00:00 2001 From: Dmitriy Kumshayev Date: Thu, 27 Jun 2024 13:42:35 +0100 Subject: [PATCH 1/3] Fallible actions support --- CHANGELOG.md | 1 + examples/async.rs | 10 +++--- examples/context.rs | 6 ++-- examples/dominos.rs | 16 ++++----- examples/event_with_data.rs | 3 +- examples/event_with_mutable_data.rs | 3 +- examples/event_with_reference_data.rs | 6 ++-- examples/ex3.rs | 6 ++-- examples/guard_action_syntax.rs | 4 +-- ...rd_action_syntax_with_temporary_context.rs | 11 ++++-- examples/guard_custom_error.rs | 4 +-- examples/named_async.rs | 16 +++++---- examples/named_dominos.rs | 16 ++++----- examples/named_ex3.rs | 6 ++-- examples/named_state_with_data.rs | 4 +-- examples/named_state_with_reference_data.rs | 4 +-- examples/reuse_action.rs | 3 +- examples/starting_state_with_data.rs | 4 +-- examples/state_machine_logger.rs | 7 ++-- examples/state_with_data.rs | 4 +-- examples/state_with_reference_data.rs | 4 +-- macros/src/codegen.rs | 35 +++++++++---------- tests/test.rs | 29 +++++++++------ 23 files changed, 116 insertions(+), 86 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index faf5582..88a2fc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ process. - `StateMachine::new` and `StateMachine::new_with_state` are now const functions - Fixed clippy warnings - [breaking] Changed guard functions return type from Result<(),_> to Result +- [breaking] Changed action functions return type from () to Result ## [v0.6.0] - 2022-11-02 diff --git a/examples/async.rs b/examples/async.rs index 7e7e357..e13bbe0 100644 --- a/examples/async.rs +++ b/examples/async.rs @@ -39,22 +39,24 @@ impl StateMachineContext for Context { Ok(true) } - async fn action2(&mut self) -> () { + async fn action2(&mut self) -> Result<(), ()> { println!("`action2` called from async context"); if !*self.lock.read().await { self.done = true; } + Ok(()) } - async fn action1(&mut self) -> () { + async fn action1(&mut self) -> Result<(), ()> { println!("`action1` called from async context"); let mut lock = self.lock.write().await; *lock = true; + Ok(()) } - fn action3(&mut self) -> bool { + fn action3(&mut self) -> Result { println!("`action3` called from sync context, done = `{}`", self.done); - self.done + Ok(self.done) } } diff --git a/examples/context.rs b/examples/context.rs index 171abe5..f28b8a4 100644 --- a/examples/context.rs +++ b/examples/context.rs @@ -20,12 +20,14 @@ pub struct Context { } impl StateMachineContext for Context { - fn count_transition1(&mut self) { + fn count_transition1(&mut self) -> Result<(), ()> { self.num_transitions += 1; + Ok(()) } - fn count_transition2(&mut self) { + fn count_transition2(&mut self) -> Result<(), ()> { self.num_transitions += 1; + Ok(()) } } diff --git a/examples/dominos.rs b/examples/dominos.rs index e25b138..37e5d3c 100644 --- a/examples/dominos.rs +++ b/examples/dominos.rs @@ -18,20 +18,20 @@ statemachine! { pub struct Context; impl StateMachineContext for Context { - fn to_d2(&mut self) -> Option { - Some(Events::ToD2) + fn to_d2(&mut self) -> Result, ()> { + Ok(Some(Events::ToD2)) } - fn to_d3(&mut self, _state_data: &Option) -> Option { - Some(Events::ToD3) + fn to_d3(&mut self, _state_data: &Option) -> Result, ()> { + Ok(Some(Events::ToD3)) } - fn to_d4(&mut self, _state_data: &Option) -> Option { - Some(Events::ToD4) + fn to_d4(&mut self, _state_data: &Option) -> Result, ()> { + Ok(Some(Events::ToD4)) } - fn to_d5(&mut self, _state_data: &Option) -> Option { - Some(Events::ToD5) + fn to_d5(&mut self, _state_data: &Option) -> Result, ()> { + Ok(Some(Events::ToD5)) } } diff --git a/examples/event_with_data.rs b/examples/event_with_data.rs index c222973..ea50a92 100644 --- a/examples/event_with_data.rs +++ b/examples/event_with_data.rs @@ -25,8 +25,9 @@ impl StateMachineContext for Context { Ok(event_data == &MyEventData(42)) } - fn action(&mut self, event_data: MyEventData) { + fn action(&mut self, event_data: MyEventData) -> Result<(), ()> { println!("Got valid Event Data = {}", event_data.0); + Ok(()) } } diff --git a/examples/event_with_mutable_data.rs b/examples/event_with_mutable_data.rs index 560bb99..c2c8368 100644 --- a/examples/event_with_mutable_data.rs +++ b/examples/event_with_mutable_data.rs @@ -26,8 +26,9 @@ impl StateMachineContext for Context { Ok(true) } - fn action(&mut self, event_data: &mut MyEventData) { + fn action(&mut self, event_data: &mut MyEventData) -> Result<(), ()> { println!("Got valid Event Data = {}", event_data.0); + Ok(()) } } diff --git a/examples/event_with_reference_data.rs b/examples/event_with_reference_data.rs index 4c6afe9..8e69480 100644 --- a/examples/event_with_reference_data.rs +++ b/examples/event_with_reference_data.rs @@ -26,16 +26,18 @@ impl StateMachineContext for Context { Ok(!event_data.is_empty()) } - fn action1(&mut self, event_data: &[u8]) { + fn action1(&mut self, event_data: &[u8]) -> Result<(), ()> { println!("Got valid Event Data = {:?}", event_data); + Ok(()) } fn guard2(&mut self, event_data: &MyReferenceWrapper) -> Result { Ok(*event_data.0 > 9000) } - fn action2(&mut self, event_data: MyReferenceWrapper) { + fn action2(&mut self, event_data: MyReferenceWrapper) -> Result<(), ()> { println!("Got valid Event Data = {}", event_data.0); + Ok(()) } } diff --git a/examples/ex3.rs b/examples/ex3.rs index 0879ff3..10c3a36 100644 --- a/examples/ex3.rs +++ b/examples/ex3.rs @@ -28,12 +28,14 @@ impl StateMachineContext for Context { Ok(false) } - fn action1(&mut self) { + fn action1(&mut self) -> Result<(), ()> { //println!("Action 1"); + Ok(()) } - fn action2(&mut self) { + fn action2(&mut self) -> Result<(), ()> { //println!("Action 1"); + Ok(()) } } diff --git a/examples/guard_action_syntax.rs b/examples/guard_action_syntax.rs index f3b953f..77d43e0 100644 --- a/examples/guard_action_syntax.rs +++ b/examples/guard_action_syntax.rs @@ -32,7 +32,7 @@ impl StateMachineContext for Context { } // Action1 has access to the data from Event1, and need to return the state data for State2 - fn action1(&mut self, _event_data: MyEventData) -> MyStateData { + fn action1(&mut self, _event_data: MyEventData) -> Result { todo!() } @@ -42,7 +42,7 @@ impl StateMachineContext for Context { } // Action2 has access to the data from State2 - fn action2(&mut self, _state_data: &MyStateData) { + fn action2(&mut self, _state_data: &MyStateData) -> Result<(), ()> { todo!() } } diff --git a/examples/guard_action_syntax_with_temporary_context.rs b/examples/guard_action_syntax_with_temporary_context.rs index 69b4be2..a062575 100644 --- a/examples/guard_action_syntax_with_temporary_context.rs +++ b/examples/guard_action_syntax_with_temporary_context.rs @@ -35,10 +35,14 @@ impl StateMachineContext for Context { } // Action1 has access to the data from Event1, and need to return the state data for State2 - fn action1(&mut self, temp_context: &mut u16, _event_data: MyEventData) -> MyStateData { + fn action1( + &mut self, + temp_context: &mut u16, + _event_data: MyEventData, + ) -> Result { *temp_context += 1; - MyStateData(1) + Ok(MyStateData(1)) } // Guard2 has access to the data from State2 @@ -49,8 +53,9 @@ impl StateMachineContext for Context { } // Action2 has access to the data from State2 - fn action2(&mut self, temp_context: &mut u16, _state_data: &MyStateData) { + fn action2(&mut self, temp_context: &mut u16, _state_data: &MyStateData) -> Result<(), ()> { *temp_context += 1; + Ok(()) } } diff --git a/examples/guard_custom_error.rs b/examples/guard_custom_error.rs index e7437ca..e6f9839 100644 --- a/examples/guard_custom_error.rs +++ b/examples/guard_custom_error.rs @@ -40,7 +40,7 @@ impl StateMachineContext for Context { } // Action1 has access to the data from Event1, and need to return the state data for State2 - fn action1(&mut self, _event_data: MyEventData) -> MyStateData { + fn action1(&mut self, _event_data: MyEventData) -> Result { todo!() } @@ -50,7 +50,7 @@ impl StateMachineContext for Context { } // Action2 has access to the data from State2 - fn action2(&mut self, _state_data: &MyStateData) { + fn action2(&mut self, _state_data: &MyStateData) -> Result<(), Self::GuardError> { todo!() } } diff --git a/examples/named_async.rs b/examples/named_async.rs index e34f201..ac03063 100644 --- a/examples/named_async.rs +++ b/examples/named_async.rs @@ -35,22 +35,24 @@ impl AsyncSimpleStateMachineContext for Context { Ok(true) } - async fn action1(&mut self) -> () { + fn action3(&mut self) -> Result { + println!("`action3` called from sync context, done = `{}`", self.done); + Ok(self.done) + } + + async fn action1(&mut self) -> Result<(), ()> { println!("`action1` called from async context"); let mut lock = self.lock.write().await; *lock = true; + Ok(()) } - fn action3(&mut self) -> bool { - println!("`action3` called from sync context, done = `{}`", self.done); - self.done - } - - async fn action2(&mut self) -> () { + async fn action2(&mut self) -> Result<(), ()> { println!("`action2` called from async context"); if !*self.lock.read().await { self.done = true; } + Ok(()) } } diff --git a/examples/named_dominos.rs b/examples/named_dominos.rs index 8b258d1..a250e5b 100644 --- a/examples/named_dominos.rs +++ b/examples/named_dominos.rs @@ -19,20 +19,20 @@ statemachine! { pub struct Context; impl DominosStateMachineContext for Context { - fn to_d2(&mut self) -> Option { - Some(DominosEvents::ToD2) + fn to_d2(&mut self) -> Result, ()> { + Ok(Some(DominosEvents::ToD2)) } - fn to_d3(&mut self, _state_data: &Option) -> Option { - Some(DominosEvents::ToD3) + fn to_d3(&mut self, _state_data: &Option) -> Result, ()> { + Ok(Some(DominosEvents::ToD3)) } - fn to_d4(&mut self, _state_data: &Option) -> Option { - Some(DominosEvents::ToD4) + fn to_d4(&mut self, _state_data: &Option) -> Result, ()> { + Ok(Some(DominosEvents::ToD4)) } - fn to_d5(&mut self, _state_data: &Option) -> Option { - Some(DominosEvents::ToD5) + fn to_d5(&mut self, _state_data: &Option) -> Result, ()> { + Ok(Some(DominosEvents::ToD5)) } } diff --git a/examples/named_ex3.rs b/examples/named_ex3.rs index 7ae0ce7..062ce30 100644 --- a/examples/named_ex3.rs +++ b/examples/named_ex3.rs @@ -29,12 +29,14 @@ impl LoopingWithGuardsStateMachineContext for Context { Ok(false) } - fn action1(&mut self) { + fn action1(&mut self) -> Result<(), ()> { //println!("Action 1"); + Ok(()) } - fn action2(&mut self) { + fn action2(&mut self) -> Result<(), ()> { //println!("Action 1"); + Ok(()) } } diff --git a/examples/named_state_with_data.rs b/examples/named_state_with_data.rs index 9d73237..08edfa9 100644 --- a/examples/named_state_with_data.rs +++ b/examples/named_state_with_data.rs @@ -23,8 +23,8 @@ statemachine! { pub struct Context; impl StatesWithDataStateMachineContext for Context { - fn action(&mut self) -> MyStateData { - MyStateData(42) + fn action(&mut self) -> Result { + Ok(MyStateData(42)) } } diff --git a/examples/named_state_with_reference_data.rs b/examples/named_state_with_reference_data.rs index aef713d..5dbf199 100644 --- a/examples/named_state_with_reference_data.rs +++ b/examples/named_state_with_reference_data.rs @@ -23,8 +23,8 @@ statemachine! { pub struct Context; impl StatesWithRefDataStateMachineContext for Context { - fn action<'a>(&mut self) -> MyStateData<'a> { - MyStateData(&42) + fn action<'a>(&mut self) -> Result, ()> { + Ok(MyStateData(&42)) } } diff --git a/examples/reuse_action.rs b/examples/reuse_action.rs index 46c401a..4f02d88 100644 --- a/examples/reuse_action.rs +++ b/examples/reuse_action.rs @@ -18,8 +18,9 @@ statemachine! { pub struct Context(usize); impl StateMachineContext for Context { - fn action(&mut self) { + fn action(&mut self) -> Result<(), ()> { self.0 += 1; + Ok(()) } } diff --git a/examples/starting_state_with_data.rs b/examples/starting_state_with_data.rs index 720ce45..82537f6 100644 --- a/examples/starting_state_with_data.rs +++ b/examples/starting_state_with_data.rs @@ -22,8 +22,8 @@ statemachine! { pub struct Context; impl StateMachineContext for Context { - fn action(&mut self) -> MyStateData { - MyStateData(42) + fn action(&mut self) -> Result { + Ok(MyStateData(42)) } } diff --git a/examples/state_machine_logger.rs b/examples/state_machine_logger.rs index 3374627..09a5d7c 100644 --- a/examples/state_machine_logger.rs +++ b/examples/state_machine_logger.rs @@ -35,9 +35,9 @@ impl StateMachineContext for Context { } // Action1 has access to the data from Event1, and need to return the state data for State2 - fn action1(&mut self, event_data: MyEventData) -> MyStateData { + fn action1(&mut self, event_data: MyEventData) -> Result { println!("Creating state data for next state"); - MyStateData(event_data.0) + Ok(MyStateData(event_data.0)) } // Guard2 has access to the data from State2 @@ -46,8 +46,9 @@ impl StateMachineContext for Context { } // Action2 has access to the data from State2 - fn action2(&mut self, state_data: &MyStateData) { + fn action2(&mut self, state_data: &MyStateData) -> Result<(), ()> { println!("Printing state data {:?}", state_data); + Ok(()) } fn log_process_event(&self, current_state: &States, event: &Events) { diff --git a/examples/state_with_data.rs b/examples/state_with_data.rs index fb5fb84..bb59a28 100644 --- a/examples/state_with_data.rs +++ b/examples/state_with_data.rs @@ -22,8 +22,8 @@ statemachine! { pub struct Context; impl StateMachineContext for Context { - fn action(&mut self) -> MyStateData { - MyStateData(42) + fn action(&mut self) -> Result { + Ok(MyStateData(42)) } } diff --git a/examples/state_with_reference_data.rs b/examples/state_with_reference_data.rs index 134b254..8a88a65 100644 --- a/examples/state_with_reference_data.rs +++ b/examples/state_with_reference_data.rs @@ -22,8 +22,8 @@ statemachine! { pub struct Context; impl StateMachineContext for Context { - fn action<'a>(&mut self) -> MyStateData<'a> { - MyStateData(&42) + fn action<'a>(&mut self) -> Result, ()> { + Ok(MyStateData(&42)) } } diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index 2b02d96..affd452 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -2,9 +2,9 @@ use crate::parser::transition::visit_guards; use crate::parser::{lifetimes::Lifetimes, AsyncIdent, ParsedStateMachine}; -use proc_macro2::{Span, TokenStream}; +use proc_macro2::{Ident, Span, TokenStream}; use quote::{format_ident, quote}; -use syn::{punctuated::Punctuated, token::Paren, Type, TypeTuple}; +use syn::Type; pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { let (sm_name, sm_name_span) = sm @@ -203,6 +203,12 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { }) .collect(); + let guard_error = if sm.custom_guard_error { + quote! { Self::GuardError } + } else { + quote! { () } + }; + let out_states: Vec>> = transitions .values() .map(|event_mappings| { @@ -314,12 +320,6 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { None => quote! {}, }; - let guard_error = if sm.custom_guard_error { - quote! { Self::GuardError } - } else { - quote! { () } - }; - // Only add the guard if it hasn't been added before if !guard_set.iter().any(|g| g == guard) { guard_set.push(guard.clone()); @@ -350,15 +350,10 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { .data_types .get(&transition.out_state.to_string()) { - output_data.clone() + quote! { Result<#output_data,#guard_error> } } else { // Empty return type - Type::Tuple(TypeTuple { - paren_token: Paren { - span: Span::call_site(), - }, - elems: Punctuated::new(), - }) + quote! { Result<(),#guard_error> } }; let event_data = match sm.event_data.data_types.get(event) { @@ -430,7 +425,7 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { self.context.#exit_ident(); self.context.#entry_ident(); }; - let (is_async_action, action_code) = generate_action(action, &temporary_context_call, action_params); + let (is_async_action, action_code) = generate_action(action, &temporary_context_call, action_params, &error_type_name); is_async_state_machine |= is_async_action; if let Some(expr) = guard { // Guarded transition @@ -468,7 +463,8 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { } } } else { // Unguarded transition - quote!{ + + quote!{ #action_code let out_state = #states_type_name::#out_state; self.context.log_state_change(&out_state); @@ -611,6 +607,8 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { TransitionsFailed, /// When guard is failed. GuardFailed(T), + /// When action returns Err + ActionFailed(T), } /// State machine structure definition. @@ -686,6 +684,7 @@ fn generate_action( action: &Option, temporary_context_call: &TokenStream, g_a_param: &TokenStream, + error_type_name: &Ident, ) -> (bool, TokenStream) { let mut is_async = false; let code = if let Some(AsyncIdent { @@ -701,7 +700,7 @@ fn generate_action( }; quote! { // ACTION - let _data = self.context.#action_ident(#temporary_context_call #g_a_param) #action_await; + let _data = self.context.#action_ident(#temporary_context_call #g_a_param) #action_await .map_err(#error_type_name::ActionFailed)?; self.context.log_action(stringify!(#action_ident)); } } else { diff --git a/tests/test.rs b/tests/test.rs index 7fe80b3..65a1c48 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -60,15 +60,21 @@ fn multiple_lifetimes() { Ok(true) } - fn action1<'a>(&mut self, event_data: &'a X) -> &'a X { - event_data + fn action1<'a>(&mut self, event_data: &'a X) -> Result<&'a X, ()> { + Ok(event_data) } - fn action2<'a, 'b>(&mut self, state_data: &'a X, event_data: &'b Y) -> (&'a X, &'b Y) { - (state_data, event_data) + fn action2<'a, 'b>( + &mut self, + state_data: &'a X, + event_data: &'b Y, + ) -> Result<(&'a X, &'b Y), ()> { + Ok((state_data, event_data)) } - fn action3(&mut self, _event_data: &Z) {} + fn action3(&mut self, _event_data: &Z) -> Result<(), ()> { + Ok(()) + } } #[allow(dead_code)] @@ -144,8 +150,8 @@ fn async_guards_and_actions() { Ok(true) } - async fn action1(&mut self) -> () { - () + async fn action1(&mut self) -> Result<(), ()> { + Ok(()) } } @@ -186,11 +192,13 @@ fn guard_expressions() { fn too_many_attempts(&mut self, _e: &Entry) -> Result { Ok(self.attempts >= 3) } - fn reset(&mut self) { + fn reset(&mut self) -> Result<(), ()> { self.attempts = 0; + Ok(()) } - fn attempt(&mut self, _e: &Entry) { + fn attempt(&mut self, _e: &Entry) -> Result<(), ()> { self.attempts += 1; + Ok(()) } } @@ -256,8 +264,9 @@ fn guarded_transition_before_unguarded() { Ok(self.enabled) } - fn disable(&mut self) { + fn disable(&mut self) -> Result<(), ()> { self.enabled = false; + Ok(()) } } let mut sm = StateMachine::new(Context { enabled: true }); From ab2a206d586e07e452203fbef5e9b2d41f44b294 Mon Sep 17 00:00:00 2001 From: Dmitriy Kumshayev Date: Thu, 27 Jun 2024 16:15:52 +0100 Subject: [PATCH 2/3] use non-mutable self for guards --- CHANGELOG.md | 1 + examples/async.rs | 6 +++--- examples/event_with_data.rs | 2 +- examples/event_with_mutable_data.rs | 2 +- examples/event_with_reference_data.rs | 4 ++-- examples/ex3.rs | 4 ++-- examples/guard_action_syntax.rs | 4 ++-- ...guard_action_syntax_with_temporary_context.rs | 4 ++-- examples/guard_custom_error.rs | 4 ++-- examples/named_async.rs | 4 ++-- examples/named_ex3.rs | 4 ++-- examples/state_machine_logger.rs | 4 ++-- macros/src/codegen.rs | 2 +- tests/test.rs | 16 ++++++++-------- 14 files changed, 31 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88a2fc4..36f253d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ process. - Fixed clippy warnings - [breaking] Changed guard functions return type from Result<(),_> to Result - [breaking] Changed action functions return type from () to Result +- [breaking] Disallow guards mutable access to the context ## [v0.6.0] - 2022-11-02 diff --git a/examples/async.rs b/examples/async.rs index e13bbe0..b8f2816 100644 --- a/examples/async.rs +++ b/examples/async.rs @@ -22,19 +22,19 @@ pub struct Context { #[async_trait] impl StateMachineContext for Context { - fn guard3(&mut self) -> Result { + fn guard3(&self) -> Result { println!("`guard3` called from async context"); Ok(true) } - async fn guard2(&mut self) -> Result { + async fn guard2(&self) -> Result { println!("`guard2` called from async context"); let mut lock = self.lock.write().await; *lock = false; Ok(true) } - fn guard1(&mut self) -> Result { + fn guard1(&self) -> Result { println!("`guard1` called from sync context"); Ok(true) } diff --git a/examples/event_with_data.rs b/examples/event_with_data.rs index ea50a92..367543b 100644 --- a/examples/event_with_data.rs +++ b/examples/event_with_data.rs @@ -21,7 +21,7 @@ statemachine! { pub struct Context; impl StateMachineContext for Context { - fn guard(&mut self, event_data: &MyEventData) -> Result { + fn guard(&self, event_data: &MyEventData) -> Result { Ok(event_data == &MyEventData(42)) } diff --git a/examples/event_with_mutable_data.rs b/examples/event_with_mutable_data.rs index c2c8368..2f9ec92 100644 --- a/examples/event_with_mutable_data.rs +++ b/examples/event_with_mutable_data.rs @@ -21,7 +21,7 @@ statemachine! { pub struct Context; impl StateMachineContext for Context { - fn guard(&mut self, event_data: &mut MyEventData) -> Result { + fn guard(&self, event_data: &mut MyEventData) -> Result { event_data.0 = 55; Ok(true) } diff --git a/examples/event_with_reference_data.rs b/examples/event_with_reference_data.rs index 8e69480..c2e0791 100644 --- a/examples/event_with_reference_data.rs +++ b/examples/event_with_reference_data.rs @@ -21,7 +21,7 @@ statemachine! { pub struct Context; impl StateMachineContext for Context { - fn guard1(&mut self, event_data: &[u8]) -> Result { + fn guard1(&self, event_data: &[u8]) -> Result { // Only ok if the slice is not empty Ok(!event_data.is_empty()) } @@ -31,7 +31,7 @@ impl StateMachineContext for Context { Ok(()) } - fn guard2(&mut self, event_data: &MyReferenceWrapper) -> Result { + fn guard2(&self, event_data: &MyReferenceWrapper) -> Result { Ok(*event_data.0 > 9000) } diff --git a/examples/ex3.rs b/examples/ex3.rs index 10c3a36..cfb3143 100644 --- a/examples/ex3.rs +++ b/examples/ex3.rs @@ -18,12 +18,12 @@ statemachine! { pub struct Context; impl StateMachineContext for Context { - fn guard(&mut self) -> Result { + fn guard(&self) -> Result { // Always ok Ok(true) } - fn guard_fail(&mut self) -> Result { + fn guard_fail(&self) -> Result { // Always fail Ok(false) } diff --git a/examples/guard_action_syntax.rs b/examples/guard_action_syntax.rs index 77d43e0..0fc4491 100644 --- a/examples/guard_action_syntax.rs +++ b/examples/guard_action_syntax.rs @@ -27,7 +27,7 @@ pub struct Context; impl StateMachineContext for Context { // Guard1 has access to the data from Event1 - fn guard1(&mut self, _event_data: &MyEventData) -> Result { + fn guard1(&self, _event_data: &MyEventData) -> Result { todo!() } @@ -37,7 +37,7 @@ impl StateMachineContext for Context { } // Guard2 has access to the data from State2 - fn guard2(&mut self, _state_data: &MyStateData) -> Result { + fn guard2(&self, _state_data: &MyStateData) -> Result { todo!() } diff --git a/examples/guard_action_syntax_with_temporary_context.rs b/examples/guard_action_syntax_with_temporary_context.rs index a062575..4f8b2de 100644 --- a/examples/guard_action_syntax_with_temporary_context.rs +++ b/examples/guard_action_syntax_with_temporary_context.rs @@ -28,7 +28,7 @@ pub struct Context; impl StateMachineContext for Context { // Guard1 has access to the data from Event1 - fn guard1(&mut self, temp_context: &mut u16, _event_data: &MyEventData) -> Result { + fn guard1(&self, temp_context: &mut u16, _event_data: &MyEventData) -> Result { *temp_context += 1; Ok(true) @@ -46,7 +46,7 @@ impl StateMachineContext for Context { } // Guard2 has access to the data from State2 - fn guard2(&mut self, temp_context: &mut u16, _state_data: &MyStateData) -> Result { + fn guard2(&self, temp_context: &mut u16, _state_data: &MyStateData) -> Result { *temp_context += 1; Ok(true) diff --git a/examples/guard_custom_error.rs b/examples/guard_custom_error.rs index e6f9839..e2d71d8 100644 --- a/examples/guard_custom_error.rs +++ b/examples/guard_custom_error.rs @@ -35,7 +35,7 @@ pub struct Context; impl StateMachineContext for Context { type GuardError = GuardError; // Guard1 has access to the data from Event1 - fn guard1(&mut self, _event_data: &MyEventData) -> Result { + fn guard1(&self, _event_data: &MyEventData) -> Result { Err(GuardError::Custom) } @@ -45,7 +45,7 @@ impl StateMachineContext for Context { } // Guard2 has access to the data from State2 - fn guard2(&mut self, _state_data: &MyStateData) -> Result { + fn guard2(&self, _state_data: &MyStateData) -> Result { todo!() } diff --git a/examples/named_async.rs b/examples/named_async.rs index ac03063..ea939c2 100644 --- a/examples/named_async.rs +++ b/examples/named_async.rs @@ -23,12 +23,12 @@ pub struct Context { #[async_trait] impl AsyncSimpleStateMachineContext for Context { - fn guard1(&mut self) -> Result { + fn guard1(&self) -> Result { println!("`guard1` called from sync context"); Ok(true) } - async fn guard2(&mut self) -> Result { + async fn guard2(&self) -> Result { println!("`guard2` called from async context"); let mut lock = self.lock.write().await; *lock = false; diff --git a/examples/named_ex3.rs b/examples/named_ex3.rs index 062ce30..cac36b4 100644 --- a/examples/named_ex3.rs +++ b/examples/named_ex3.rs @@ -19,12 +19,12 @@ statemachine! { pub struct Context; impl LoopingWithGuardsStateMachineContext for Context { - fn guard(&mut self) -> Result { + fn guard(&self) -> Result { // Always ok Ok(true) } - fn guard_fail(&mut self) -> Result { + fn guard_fail(&self) -> Result { // Always fail Ok(false) } diff --git a/examples/state_machine_logger.rs b/examples/state_machine_logger.rs index 09a5d7c..5fea6da 100644 --- a/examples/state_machine_logger.rs +++ b/examples/state_machine_logger.rs @@ -30,7 +30,7 @@ pub struct Context; impl StateMachineContext for Context { // Guard1 has access to the data from Event1 - fn guard1(&mut self, event_data: &MyEventData) -> Result { + fn guard1(&self, event_data: &MyEventData) -> Result { Ok(event_data.0 % 2 == 0) } @@ -41,7 +41,7 @@ impl StateMachineContext for Context { } // Guard2 has access to the data from State2 - fn guard2(&mut self, state_data: &MyStateData) -> Result { + fn guard2(&self, state_data: &MyStateData) -> Result { Ok(state_data.0 % 2 == 0) } diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index affd452..dd8e686 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -327,7 +327,7 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { guard_list.extend(quote! { #[allow(missing_docs)] #[allow(clippy::result_unit_err)] - #is_async fn #guard <#all_lifetimes> (&mut self, #temporary_context #state_data #event_data) -> Result; + #is_async fn #guard <#all_lifetimes> (&self, #temporary_context #state_data #event_data) -> Result; }); }; Ok(()) diff --git a/tests/test.rs b/tests/test.rs index 65a1c48..df81a33 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -48,15 +48,15 @@ fn multiple_lifetimes() { struct Context; impl StateMachineContext for Context { - fn guard1(&mut self, _event_data: &X) -> Result { + fn guard1(&self, _event_data: &X) -> Result { Ok(true) } - fn guard2(&mut self, _state_data: &X, _event_data: &Y) -> Result { + fn guard2(&self, _state_data: &X, _event_data: &Y) -> Result { Ok(true) } - fn guard3(&mut self, _event_data: &Z) -> Result { + fn guard3(&self, _event_data: &Z) -> Result { Ok(true) } @@ -146,7 +146,7 @@ fn async_guards_and_actions() { struct Context; #[smlang::async_trait] impl StateMachineContext for Context { - async fn guard1(&mut self) -> Result { + async fn guard1(&self) -> Result { Ok(true) } @@ -186,10 +186,10 @@ fn guard_expressions() { attempts: u32, } impl StateMachineContext for Context { - fn valid_entry(&mut self, e: &Entry) -> Result { + fn valid_entry(&self, e: &Entry) -> Result { Ok(e.0 == self.password) } - fn too_many_attempts(&mut self, _e: &Entry) -> Result { + fn too_many_attempts(&self, _e: &Entry) -> Result { Ok(self.attempts >= 3) } fn reset(&mut self) -> Result<(), ()> { @@ -260,7 +260,7 @@ fn guarded_transition_before_unguarded() { pub enabled: bool, } impl StateMachineContext for Context { - fn guard(&mut self) -> Result { + fn guard(&self) -> Result { Ok(self.enabled) } @@ -294,7 +294,7 @@ fn guard_errors() { pub guard_errors: bool, } impl StateMachineContext for Context { - fn guard(&mut self) -> Result { + fn guard(&self) -> Result { if self.guard_errors { Err(()) } else { From 675763b917cc57f3d8f634a3b8da3a292e25f26b Mon Sep 17 00:00:00 2001 From: Dmitriy Kumshayev Date: Thu, 27 Jun 2024 16:26:38 +0100 Subject: [PATCH 3/3] renamed GuardError to Error to be used with both guards and actions --- CHANGELOG.md | 1 + examples/guard_custom_error.rs | 6 +++--- macros/src/codegen.rs | 8 ++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36f253d..eb02bea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ process. - [breaking] Changed guard functions return type from Result<(),_> to Result - [breaking] Changed action functions return type from () to Result - [breaking] Disallow guards mutable access to the context +- [breaking] Renamed GuardError to Error as it is now used for both guards and actions ## [v0.6.0] - 2022-11-02 diff --git a/examples/guard_custom_error.rs b/examples/guard_custom_error.rs index e2d71d8..b8e85a4 100644 --- a/examples/guard_custom_error.rs +++ b/examples/guard_custom_error.rs @@ -34,13 +34,13 @@ statemachine! { pub struct Context; impl StateMachineContext for Context { - type GuardError = GuardError; // Guard1 has access to the data from Event1 + type Error = GuardError; // Guard1 has access to the data from Event1 fn guard1(&self, _event_data: &MyEventData) -> Result { Err(GuardError::Custom) } // Action1 has access to the data from Event1, and need to return the state data for State2 - fn action1(&mut self, _event_data: MyEventData) -> Result { + fn action1(&mut self, _event_data: MyEventData) -> Result { todo!() } @@ -50,7 +50,7 @@ impl StateMachineContext for Context { } // Action2 has access to the data from State2 - fn action2(&mut self, _state_data: &MyStateData) -> Result<(), Self::GuardError> { + fn action2(&mut self, _state_data: &MyStateData) -> Result<(), Self::Error> { todo!() } } diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index dd8e686..f8ecbc0 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -204,7 +204,7 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { .collect(); let guard_error = if sm.custom_guard_error { - quote! { Self::GuardError } + quote! { Self::Error } } else { quote! { () } }; @@ -516,8 +516,8 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { let guard_error = if sm.custom_guard_error { quote! { - /// The error type returned by guard functions. - type GuardError: core::fmt::Debug; + /// The error type returned by guard or action functions. + type Error: core::fmt::Debug; } } else { quote! {} @@ -531,7 +531,7 @@ pub fn generate_code(sm: &ParsedStateMachine) -> proc_macro2::TokenStream { let error_type = if sm.custom_guard_error { quote! { - #error_type_name<::GuardError> + #error_type_name<::Error> } } else { quote! {#error_type_name}