eugene-babichenko / rust-fsm Goto Github PK
View Code? Open in Web Editor NEWFinite state machine framework for Rust with readable specifications
License: MIT License
Finite state machine framework for Rust with readable specifications
License: MIT License
Hi,
I made a quick hack that produces state machine graph from state machines defined using the DSL. It currently produces graphviz .dot files which can be rendered to images in a plethora of formats - png, svg, ps, pdf etc. As an example, for the example in rust-fsm's README.md, it produces a CircuitBreaker.dot
file:
digraph "graph" {
rankdir="LR";
SM_init [label="", shape=point];
SM_init -> "Closed";
"Closed" -> "Open" [label="Unsuccessful [SetupTimer]" minlen=2];
"Open" -> "HalfOpen" [label="TimerTriggered" minlen=2];
"HalfOpen" -> "Closed" [label="Successful" minlen=2];
"HalfOpen" -> "Open" [label="Unsuccessful [SetupTimer]" minlen=2];
}
.. which using the dot -Tpng CircuitBreaker.dot > CircuitBreaker.png
command from the graphviz package generates the following image:
The code is available here; I copy-pasted the parser.rs
module from your project because it was not exported.
I post this issue hoping to receive feedback from you on this; would any of the following options be interesting to you?
The tool could be further improved for example perhaps by e.g. seamlessly integrating it to the cargo doc
or similar so the graphs could be part of the crate's documentation if wanted.
This crate is great and I'd love to use it, but it seems like its design limits the ability to have the states store data that can be used to calculate outputs. In particular it seems that the only way to get data into the state machine at all is to include it as part of the Input
type, for example having Input
be an enum
type where the variants have data. However, StateMachine::consume
only takes an immutable reference to Input
so it's basically impossible to move data from the Input
to the State
without copying it. Similarly, because StateMachineImpl::transition
gets an immutable reference to the Input
and the State
, it's again not possible to move data from one state to another and/or from the Input
without copying.
I realize that this would be a breaking change, but to me it makes more sense to always use owned version of Input
instead of immutable references since the user could just use an immutable reference itself as Input
if that's what they wanted to do. The State
issue is tricky on account of the fact that StateMachineImpl::transition
may or may not need to make a new State
from the old one. Again, it would be nice to be able to move data from the old state to the new one in this case, but I'm not sure how that could be handled since, if the state is not transitioning, the old State
needs to be retained and therefore cannot be moved into transition
.
It may be that this crate is really just intended to be used for data-less state machines so I'm trying to do something it was not really intended to do. This is fine since I can always use the Typestate pattern.
Hello,
I'm not super familiar with Rust, so I may be missing something obvious here, but I tried to get set up with this using the DSL and ran into errors, so I tried to run the example and ran into the same errors. Here's my main.rs
, which is just the two sections from the README pasted together, I'm using 0.6.0 but had the same issues with 0.5.0:
use rust_fsm::*;
state_machine! {
derive(Debug)
CircuitBreaker(Closed)
Closed(Unsuccessful) => Open [SetupTimer],
Open(TimerTriggered) => HalfOpen,
HalfOpen => {
Successful => Closed,
Unsuccessful => Open [SetupTimer],
}
}
fn main() {
// Initialize the state machine. The state is `Closed` now.
let mut machine: StateMachine<CircuitBreaker> = StateMachine::new();
// Consume the `Successful` input. No state transition is performed.
let _ = machine.consume(&CircuitBreakerInput::Successful);
// Consume the `Unsuccesful` input. The machine is moved to the `Open`
// state. The output is `SetupTimer`.
let output = machine.consume(&CircuitBreakerInput::Unsuccesful).unwrap();
// Check the output
if output == Some(CircuitBreakerOutput::SetupTimer) {
// Set up the timer...
}
// Check the state
if machine.state() == &CircuitBreakerState::Open {
// Do something...
}
}
And cargo run
gets me the following errors:
in parse/ on master
› cargo run
Compiling parse v0.1.0 (/store/data/discogs/parse)
error[E0599]: no variant or associated item named `Unsuccesful` found for enum `CircuitBreakerInput` in the current scope
--> src/main.rs:22:56
|
3 | state_machine! {
| -------------- variant or associated item `Unsuccesful` not found here
...
22 | let output = machine.consume(&CircuitBreakerInput::Unsuccesful).unwrap();
| ^^^^^^^^^^^
| |
| variant or associated item not found in `CircuitBreakerInput`
| help: there is a variant with a similar name: `Unsuccessful`
error[E0369]: binary operation `==` cannot be applied to type `Option<CircuitBreakerOutput>`
--> src/main.rs:24:15
|
24 | if output == Some(CircuitBreakerOutput::SetupTimer) {
| ------ ^^ -------------------------------------- Option<CircuitBreakerOutput>
| |
| Option<CircuitBreakerOutput>
error[E0369]: binary operation `==` cannot be applied to type `&CircuitBreakerState`
--> src/main.rs:28:24
|
28 | if machine.state() == &CircuitBreakerState::Open {
| --------------- ^^ -------------------------- &CircuitBreakerState
| |
| &CircuitBreakerState
|
= note: an implementation of `std::cmp::PartialEq` might be missing for `&CircuitBreakerState`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0369, E0599.
For more information about an error, try `rustc --explain E0369`.
error: could not compile `parse`
To learn more, run the command again with --verbose.
I would expect the macro to set up at least implement PartialEq
for the state enums(?) but I'm not sure how to dig deeper here to see what's going on.
I'm making a parser that uses rust-fsm
to guide the consumption of my token stream. It'd be convenient if I could have my FSM use my TokenType as the input.
A catch is that the input type would have to be an enum without constructors, however a derive should be able to verify that that is the case. Alternatively, simply document that the DSL will assume it is.
The rust-fsm-dsl crate depends on quote
and syn
0.x versions, and most other clients of quote
and syn
crates have upgraded to 1.x versions. So it would be better to upgrade to 1.x to avoid multiple versions of dependent crates.
Steps to reproduce
rust-fsm = { version = "0.5", default-features = false, features = ["dsl"] }
error[E0463]: can't find crate for `std`
|
= note: the `thumbv7m-none-eabi` target may not support the standard library
= note: `std` is required by `arrayvec` because it does not declare `#![no_std]`
...
error: aborting due to 289 previous errors
Some errors have detailed explanations: E0405, E0412, E0425, E0433, E0463, E0531.
For more information about an error, try `rustc --explain E0405`.
error: could not compile `arrayvec` due to 290 previous errors
Process finished with exit code 101
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.