Finite state machines in rust; bendns fork to add types.
implement basic proper error type for impossible state transitions
Yevhenii Babichenko 2021-02-24
parent ee6dcef · commit 9f0f697
-rw-r--r--CHANGELOG.md3
-rw-r--r--src/lib.rs23
-rw-r--r--tests/circuit_breaker.rs2
-rw-r--r--tests/circuit_breaker_dsl.rs2
4 files changed, 26 insertions, 4 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 67f292a..d57a05a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,9 @@ The format is based on [Keep a Changelog][keepachangelog], and this project
adheres to [Semantic Versioning][semver].
## [Unreleased]
+### Changed
+* State transition error is now represented with `TransitionImpossibleError`
+ instead of `()`.
## [0.4.0] - 2020-08-25
### Added
diff --git a/src/lib.rs b/src/lib.rs
index 31ee638..d750135 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -113,6 +113,8 @@
//!
//! [repo]: https://github.com/eugene-babichenko/rust-fsm/blob/master/tests/circuit_breaker.rs
+use core::fmt;
+
#[doc(hidden)]
pub use rust_fsm_dsl::*;
@@ -147,6 +149,11 @@ pub struct StateMachine<T: StateMachineImpl> {
state: T::State,
}
+#[derive(Debug, Clone)]
+/// An error type that represents that the state transition is impossible given
+/// the current combination of state and input.
+pub struct TransitionImpossibleError;
+
impl<T> StateMachine<T>
where
T: StateMachineImpl,
@@ -166,13 +173,16 @@ where
/// Consumes the provided input, gives an output and performs a state
/// transition. If a state transition with the current state and the
/// provided input is not allowed, returns an error.
- pub fn consume(&mut self, input: &T::Input) -> Result<Option<T::Output>, ()> {
+ pub fn consume(
+ &mut self,
+ input: &T::Input,
+ ) -> Result<Option<T::Output>, TransitionImpossibleError> {
if let Some(state) = T::transition(&self.state, input) {
let output = T::output(&self.state, input);
self.state = state;
Ok(output)
} else {
- Err(())
+ Err(TransitionImpossibleError)
}
}
@@ -190,3 +200,12 @@ where
Self::new()
}
}
+
+impl fmt::Display for TransitionImpossibleError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "cannot perform a state transition from the current state with the provided input"
+ )
+ }
+}
diff --git a/tests/circuit_breaker.rs b/tests/circuit_breaker.rs
index a87921b..aa25a1e 100644
--- a/tests/circuit_breaker.rs
+++ b/tests/circuit_breaker.rs
@@ -91,7 +91,7 @@ fn circuit_breaker() {
std::thread::sleep(Duration::new(1, 0));
let mut lock = machine_try.lock().unwrap();
let res = lock.consume(&CircuitBreakerInput::Successful);
- assert_eq!(res, Err(()));
+ assert!(matches!(res, Err(TransitionImpossibleError)));
assert_eq!(lock.state(), &CircuitBreakerState::Open);
});
diff --git a/tests/circuit_breaker_dsl.rs b/tests/circuit_breaker_dsl.rs
index e593625..2293786 100644
--- a/tests/circuit_breaker_dsl.rs
+++ b/tests/circuit_breaker_dsl.rs
@@ -45,7 +45,7 @@ fn circit_breaker_dsl() {
std::thread::sleep(Duration::new(1, 0));
let mut lock = machine_try.lock().unwrap();
let res = lock.consume(&CircuitBreakerInput::Successful);
- assert!(matches!(res, Err(())));
+ assert!(matches!(res, Err(TransitionImpossibleError)));
assert!(matches!(lock.state(), &CircuitBreakerState::Open));
});