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

Fallible actions support #73

Merged
merged 3 commits into from
Jul 2, 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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ 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<bool,_>
- [breaking] Changed action functions return type from () to Result<NextStateData,_>
- [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

Expand Down
16 changes: 9 additions & 7 deletions examples/async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,41 @@ pub struct Context {

#[async_trait]
impl StateMachineContext for Context {
fn guard3(&mut self) -> Result<bool, ()> {
fn guard3(&self) -> Result<bool, ()> {
println!("`guard3` called from async context");
Ok(true)
}

async fn guard2(&mut self) -> Result<bool, ()> {
async fn guard2(&self) -> Result<bool, ()> {
println!("`guard2` called from async context");
let mut lock = self.lock.write().await;
*lock = false;
Ok(true)
}

fn guard1(&mut self) -> Result<bool, ()> {
fn guard1(&self) -> Result<bool, ()> {
println!("`guard1` called from sync 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<bool, ()> {
println!("`action3` called from sync context, done = `{}`", self.done);
self.done
Ok(self.done)
}
}

Expand Down
6 changes: 4 additions & 2 deletions examples/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
}

Expand Down
16 changes: 8 additions & 8 deletions examples/dominos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ statemachine! {
pub struct Context;

impl StateMachineContext for Context {
fn to_d2(&mut self) -> Option<Events> {
Some(Events::ToD2)
fn to_d2(&mut self) -> Result<Option<Events>, ()> {
Ok(Some(Events::ToD2))
}

fn to_d3(&mut self, _state_data: &Option<Events>) -> Option<Events> {
Some(Events::ToD3)
fn to_d3(&mut self, _state_data: &Option<Events>) -> Result<Option<Events>, ()> {
Ok(Some(Events::ToD3))
}

fn to_d4(&mut self, _state_data: &Option<Events>) -> Option<Events> {
Some(Events::ToD4)
fn to_d4(&mut self, _state_data: &Option<Events>) -> Result<Option<Events>, ()> {
Ok(Some(Events::ToD4))
}

fn to_d5(&mut self, _state_data: &Option<Events>) -> Option<Events> {
Some(Events::ToD5)
fn to_d5(&mut self, _state_data: &Option<Events>) -> Result<Option<Events>, ()> {
Ok(Some(Events::ToD5))
}
}

Expand Down
5 changes: 3 additions & 2 deletions examples/event_with_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ statemachine! {
pub struct Context;

impl StateMachineContext for Context {
fn guard(&mut self, event_data: &MyEventData) -> Result<bool, ()> {
fn guard(&self, event_data: &MyEventData) -> Result<bool, ()> {
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(())
}
}

Expand Down
5 changes: 3 additions & 2 deletions examples/event_with_mutable_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ statemachine! {
pub struct Context;

impl StateMachineContext for Context {
fn guard(&mut self, event_data: &mut MyEventData) -> Result<bool, ()> {
fn guard(&self, event_data: &mut MyEventData) -> Result<bool, ()> {
event_data.0 = 55;
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(())
}
}

Expand Down
10 changes: 6 additions & 4 deletions examples/event_with_reference_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,23 @@ statemachine! {
pub struct Context;

impl StateMachineContext for Context {
fn guard1(&mut self, event_data: &[u8]) -> Result<bool, ()> {
fn guard1(&self, event_data: &[u8]) -> Result<bool, ()> {
// Only ok if the slice is not empty
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<bool, ()> {
fn guard2(&self, event_data: &MyReferenceWrapper) -> Result<bool, ()> {
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(())
}
}

Expand Down
10 changes: 6 additions & 4 deletions examples/ex3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,24 @@ statemachine! {
pub struct Context;

impl StateMachineContext for Context {
fn guard(&mut self) -> Result<bool, ()> {
fn guard(&self) -> Result<bool, ()> {
// Always ok
Ok(true)
}

fn guard_fail(&mut self) -> Result<bool, ()> {
fn guard_fail(&self) -> Result<bool, ()> {
// Always fail
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(())
}
}

Expand Down
8 changes: 4 additions & 4 deletions examples/guard_action_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,22 @@ pub struct Context;

impl StateMachineContext for Context {
// Guard1 has access to the data from Event1
fn guard1(&mut self, _event_data: &MyEventData) -> Result<bool, ()> {
fn guard1(&self, _event_data: &MyEventData) -> Result<bool, ()> {
todo!()
}

// 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<MyStateData, ()> {
todo!()
}

// Guard2 has access to the data from State2
fn guard2(&mut self, _state_data: &MyStateData) -> Result<bool, ()> {
fn guard2(&self, _state_data: &MyStateData) -> Result<bool, ()> {
todo!()
}

// Action2 has access to the data from State2
fn action2(&mut self, _state_data: &MyStateData) {
fn action2(&mut self, _state_data: &MyStateData) -> Result<(), ()> {
todo!()
}
}
Expand Down
15 changes: 10 additions & 5 deletions examples/guard_action_syntax_with_temporary_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,34 @@ 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<bool, ()> {
fn guard1(&self, temp_context: &mut u16, _event_data: &MyEventData) -> Result<bool, ()> {
*temp_context += 1;

Ok(true)
}

// 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<MyStateData, ()> {
*temp_context += 1;

MyStateData(1)
Ok(MyStateData(1))
}

// Guard2 has access to the data from State2
fn guard2(&mut self, temp_context: &mut u16, _state_data: &MyStateData) -> Result<bool, ()> {
fn guard2(&self, temp_context: &mut u16, _state_data: &MyStateData) -> Result<bool, ()> {
*temp_context += 1;

Ok(true)
}

// 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(())
}
}

Expand Down
10 changes: 5 additions & 5 deletions examples/guard_custom_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,23 @@ statemachine! {
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<bool, GuardError> {
type Error = GuardError; // Guard1 has access to the data from Event1
fn guard1(&self, _event_data: &MyEventData) -> Result<bool, GuardError> {
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) -> MyStateData {
fn action1(&mut self, _event_data: MyEventData) -> Result<MyStateData, Self::Error> {
todo!()
}

// Guard2 has access to the data from State2
fn guard2(&mut self, _state_data: &MyStateData) -> Result<bool, GuardError> {
fn guard2(&self, _state_data: &MyStateData) -> Result<bool, GuardError> {
todo!()
}

// Action2 has access to the data from State2
fn action2(&mut self, _state_data: &MyStateData) {
fn action2(&mut self, _state_data: &MyStateData) -> Result<(), Self::Error> {
todo!()
}
}
Expand Down
20 changes: 11 additions & 9 deletions examples/named_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,34 +23,36 @@ pub struct Context {

#[async_trait]
impl AsyncSimpleStateMachineContext for Context {
fn guard1(&mut self) -> Result<bool, ()> {
fn guard1(&self) -> Result<bool, ()> {
println!("`guard1` called from sync context");
Ok(true)
}

async fn guard2(&mut self) -> Result<bool, ()> {
async fn guard2(&self) -> Result<bool, ()> {
println!("`guard2` called from async context");
let mut lock = self.lock.write().await;
*lock = false;
Ok(true)
}

async fn action1(&mut self) -> () {
fn action3(&mut self) -> Result<bool, ()> {
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(())
}
}

Expand Down
16 changes: 8 additions & 8 deletions examples/named_dominos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ statemachine! {
pub struct Context;

impl DominosStateMachineContext for Context {
fn to_d2(&mut self) -> Option<DominosEvents> {
Some(DominosEvents::ToD2)
fn to_d2(&mut self) -> Result<Option<DominosEvents>, ()> {
Ok(Some(DominosEvents::ToD2))
}

fn to_d3(&mut self, _state_data: &Option<DominosEvents>) -> Option<DominosEvents> {
Some(DominosEvents::ToD3)
fn to_d3(&mut self, _state_data: &Option<DominosEvents>) -> Result<Option<DominosEvents>, ()> {
Ok(Some(DominosEvents::ToD3))
}

fn to_d4(&mut self, _state_data: &Option<DominosEvents>) -> Option<DominosEvents> {
Some(DominosEvents::ToD4)
fn to_d4(&mut self, _state_data: &Option<DominosEvents>) -> Result<Option<DominosEvents>, ()> {
Ok(Some(DominosEvents::ToD4))
}

fn to_d5(&mut self, _state_data: &Option<DominosEvents>) -> Option<DominosEvents> {
Some(DominosEvents::ToD5)
fn to_d5(&mut self, _state_data: &Option<DominosEvents>) -> Result<Option<DominosEvents>, ()> {
Ok(Some(DominosEvents::ToD5))
}
}

Expand Down
10 changes: 6 additions & 4 deletions examples/named_ex3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,24 @@ statemachine! {
pub struct Context;

impl LoopingWithGuardsStateMachineContext for Context {
fn guard(&mut self) -> Result<bool, ()> {
fn guard(&self) -> Result<bool, ()> {
// Always ok
Ok(true)
}

fn guard_fail(&mut self) -> Result<bool, ()> {
fn guard_fail(&self) -> Result<bool, ()> {
// Always fail
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(())
}
}

Expand Down
Loading