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

Support multiple guarded transitions triggered by the same event #72

Merged
merged 16 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ Cargo.lock
*.gv
*.svg
.vscode
.idea/
31 changes: 31 additions & 0 deletions .justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# print options
dkumsh marked this conversation as resolved.
Show resolved Hide resolved
default:
@just --list --unsorted

# install cargo tools
init:
cargo upgrade --incompatible
cargo update

# check code
check:
cargo check
cargo fmt --all -- --check
cargo clippy --all-targets --all-features

# fix clippy and fmt issues
fix:
cargo clippy --allow-dirty --allow-staged --fix
cargo fmt --all

# build project
build:
cargo build --all-targets

# execute tests
test:
cargo test

# execute benchmarks
bench:
cargo bench
8 changes: 4 additions & 4 deletions examples/async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ pub struct Context {

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

async fn action1(&mut self) -> () {
Expand All @@ -33,11 +33,11 @@ impl StateMachineContext for Context {
*lock = true;
}

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

async fn action2(&mut self) -> () {
Expand Down
10 changes: 3 additions & 7 deletions examples/event_with_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,8 @@ statemachine! {
pub struct Context;

impl StateMachineContext for Context {
fn guard(&mut self, event_data: &MyEventData) -> Result<(), ()> {
if event_data == &MyEventData(42) {
Ok(())
} else {
Err(())
}
fn guard(&mut self, event_data: &MyEventData) -> bool {
event_data == &MyEventData(42)
}

fn action(&mut self, event_data: MyEventData) {
Expand All @@ -38,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_mutable_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ statemachine! {
pub struct Context;

impl StateMachineContext for Context {
fn guard(&mut self, event_data: &mut MyEventData) -> Result<(), ()> {
fn guard(&mut self, event_data: &mut MyEventData) -> bool {
event_data.0 = 55;
Ok(())
true
}

fn action(&mut self, event_data: &mut MyEventData) {
Expand Down
20 changes: 6 additions & 14 deletions examples/event_with_reference_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,17 @@ statemachine! {
pub struct Context;

impl StateMachineContext for Context {
fn guard1(&mut self, event_data: &[u8]) -> Result<(), ()> {
fn guard1(&mut self, event_data: &[u8]) -> bool {
// Only ok if the slice is not empty
if !event_data.is_empty() {
Ok(())
} else {
Err(())
}
!event_data.is_empty()
}

fn action1(&mut self, event_data: &[u8]) {
println!("Got valid Event Data = {:?}", event_data);
}

fn guard2(&mut self, event_data: &MyReferenceWrapper) -> Result<(), ()> {
if *event_data.0 > 9000 {
Ok(())
} else {
Err(())
}
fn guard2(&mut self, event_data: &MyReferenceWrapper) -> bool {
*event_data.0 > 9000
}

fn action2(&mut self, event_data: MyReferenceWrapper) {
Expand All @@ -51,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
10 changes: 5 additions & 5 deletions examples/ex3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ statemachine! {
pub struct Context;

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

fn guard_fail(&mut self) -> Result<(), ()> {
fn guard_fail(&mut self) -> bool {
// Always fail
Err(())
false
}

fn action1(&mut self) {
Expand Down 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
4 changes: 2 additions & 2 deletions examples/guard_action_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(&mut self, _event_data: &MyEventData) -> bool {
todo!()
}

Expand All @@ -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(&mut self, _state_data: &MyStateData) -> bool {
todo!()
}

Expand Down
8 changes: 4 additions & 4 deletions examples/guard_action_syntax_with_temporary_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ 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(&mut self, temp_context: &mut u16, _event_data: &MyEventData) -> bool {
*temp_context += 1;

Ok(())
true
}

// Action1 has access to the data from Event1, and need to return the state data for State2
Expand All @@ -42,10 +42,10 @@ 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(&mut self, temp_context: &mut u16, _state_data: &MyStateData) -> bool {
*temp_context += 1;

Ok(())
true
}

// Action2 has access to the data from State2
Expand Down
10 changes: 4 additions & 6 deletions examples/guard_custom_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,9 @@ 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<(), GuardError> {
Err(GuardError::Custom)
fn guard1(&mut self, _event_data: &MyEventData) -> bool {
false
}

// Action1 has access to the data from Event1, and need to return the state data for State2
Expand All @@ -47,7 +45,7 @@ impl StateMachineContext for Context {
}

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

Expand All @@ -62,5 +60,5 @@ fn main() {

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

assert!(matches!(r, Err(Error::GuardFailed(GuardError::Custom))));
assert!(matches!(r, Err(Error::TransitionsFailed)));
}
24 changes: 12 additions & 12 deletions examples/named_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,16 @@ pub struct Context {

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

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

async fn action1(&mut self) -> () {
Expand All @@ -34,11 +41,9 @@ impl AsyncSimpleStateMachineContext for Context {
*lock = true;
}

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

async fn action2(&mut self) -> () {
Expand All @@ -47,11 +52,6 @@ impl AsyncSimpleStateMachineContext for Context {
self.done = true;
}
}

fn action3(&mut self) -> bool {
println!("`action3` called from sync context, done = `{}`", self.done);
self.done
}
}

fn main() {
Expand Down
10 changes: 5 additions & 5 deletions examples/named_ex3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ statemachine! {
pub struct Context;

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

fn guard_fail(&mut self) -> Result<(), ()> {
fn guard_fail(&mut self) -> bool {
// Always fail
Err(())
false
}

fn action1(&mut self) {
Expand Down 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
20 changes: 6 additions & 14 deletions examples/state_machine_logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,8 @@ pub struct Context;

impl StateMachineContext for Context {
// Guard1 has access to the data from Event1
fn guard1(&mut self, event_data: &MyEventData) -> Result<(), ()> {
if event_data.0 % 2 == 0 {
Ok(())
} else {
Err(())
}
fn guard1(&mut self, event_data: &MyEventData) -> bool {
event_data.0 % 2 == 0
}

// Action1 has access to the data from Event1, and need to return the state data for State2
Expand All @@ -45,12 +41,8 @@ impl StateMachineContext for Context {
}

// Guard2 has access to the data from State2
fn guard2(&mut self, state_data: &MyStateData) -> Result<(), ()> {
if state_data.0 % 2 == 0 {
Ok(())
} else {
Err(())
}
fn guard2(&mut self, state_data: &MyStateData) -> bool {
state_data.0 % 2 == 0
}

// Action2 has access to the data from State2
Expand All @@ -65,8 +57,8 @@ impl StateMachineContext for Context {
);
}

fn log_guard(&self, guard: &'static str, result: &Result<(), ()>) {
if result.is_ok() {
fn log_guard(&self, guard: &'static str, result: &bool) {
if *result {
println!("[StateMachineLogger]\tPassed `{}`", guard);
} else {
println!("[StateMachineLogger]\tFailed `{}`", guard);
Expand Down
Loading
Loading