Finite state machines in rust; bendns fork to add types.
-rw-r--r--doc-example/src/lib.rs2
-rw-r--r--rust-fsm-dsl/src/lib.rs26
-rw-r--r--rust-fsm-dsl/src/parser.rs40
-rw-r--r--rust-fsm/src/lib.rs9
-rw-r--r--rust-fsm/tests/circuit_breaker_dsl.rs4
-rw-r--r--rust-fsm/tests/simple.rs4
6 files changed, 39 insertions, 46 deletions
diff --git a/doc-example/src/lib.rs b/doc-example/src/lib.rs
index c34c52e..e6621c3 100644
--- a/doc-example/src/lib.rs
+++ b/doc-example/src/lib.rs
@@ -4,7 +4,7 @@ state_machine! {
/// A dummy implementation of the Circuit Breaker pattern to demonstrate
/// capabilities of its library DSL for defining finite state machines.
/// https://martinfowler.com/bliki/CircuitBreaker.html
- pub CircuitBreaker => Result => Action
+ pub CircuitBreaker => pub Result => pub Action
Closed => Unsuccessful => Open [SetupTimer],
Open => TimerTriggered => HalfOpen,
diff --git a/rust-fsm-dsl/src/lib.rs b/rust-fsm-dsl/src/lib.rs
index 1c9fe36..094e3b2 100644
--- a/rust-fsm-dsl/src/lib.rs
+++ b/rust-fsm-dsl/src/lib.rs
@@ -32,16 +32,13 @@ fn attrs_to_token_stream(attrs: Vec<Attribute>) -> proc_macro2::TokenStream {
pub fn state_machine(tokens: TokenStream) -> TokenStream {
let StateMachineDef {
doc,
- visibility,
- state_name,
- input_name,
- output_name,
+ state_name: (state_attrs, state_visibility, state_name),
+ input_name: (input_attrs, input_visibility, input_name),
+ output_name: (output_attrs, output_visibility, output_name),
transitions,
- attributes,
} = parse_macro_input!(tokens as parser::StateMachineDef);
let doc = attrs_to_token_stream(doc);
- let attrs = attrs_to_token_stream(attributes);
if transitions.is_empty() {
let output = quote! {
@@ -168,10 +165,11 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
.unwrap();
let input_generics = input_name.g();
let input_impl = variant::tokenize(&inputs, |x| {
+ let attrs = attrs_to_token_stream(input_attrs);
input_name.tokenize(|f| {
quote! {
#attrs
- #visibility enum #f #input_generics {
+ #input_visibility enum #f #input_generics {
#(#x),*
}
}
@@ -179,10 +177,11 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
});
let input_name = input_name.path();
let state_impl = variant::tokenize(&states, |x| {
+ let attrs = attrs_to_token_stream(state_attrs.clone());
state_name.tokenize(|f| {
quote! {
#attrs
- #visibility enum #f {
+ #state_visibility enum #f {
#(#x),*
}
}
@@ -191,18 +190,11 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
let state_name = state_name.path();
let output_generics = output_name.g();
let output_impl = variant::tokenize(&outputs, |outputs| {
+ let attrs = attrs_to_token_stream(output_attrs);
output_name.tokenize(|output_name| {
- // Many attrs and derives may work incorrectly (or simply not work) for empty enums, so we just skip them
- // altogether if the output alphabet is empty.
- let attrs = if outputs.is_empty() {
- quote!()
- } else {
- attrs.clone()
- };
-
quote! {
#attrs
- #visibility enum #output_name #output_generics {
+ #output_visibility enum #output_name #output_generics {
#(#outputs),*
}
}
diff --git a/rust-fsm-dsl/src/parser.rs b/rust-fsm-dsl/src/parser.rs
index 7a25efe..aabdf88 100644
--- a/rust-fsm-dsl/src/parser.rs
+++ b/rust-fsm-dsl/src/parser.rs
@@ -117,13 +117,11 @@ impl Parse for TransitionDef {
/// ```
pub struct StateMachineDef {
pub doc: Vec<Attribute>,
- /// The visibility modifier (applies to all generated items)
- pub visibility: Visibility,
- pub state_name: ImplementationRequired,
- pub input_name: ImplementationRequired,
- pub output_name: ImplementationRequired,
+
+ pub state_name: (Vec<Attribute>, Visibility, ImplementationRequired),
+ pub input_name: (Vec<Attribute>, Visibility, ImplementationRequired),
+ pub output_name: (Vec<Attribute>, Visibility, ImplementationRequired),
pub transitions: Vec<TransitionDef>,
- pub attributes: Vec<Attribute>,
}
pub enum ImplementationRequired {
@@ -155,20 +153,20 @@ impl ImplementationRequired {
impl Parse for StateMachineDef {
fn parse(input: ParseStream) -> Result<Self> {
let mut doc = Vec::new();
- let attributes = Attribute::parse_outer(input)?
- .into_iter()
- .filter_map(|attribute| {
- if attribute.path().is_ident("doc") {
- doc.push(attribute);
- None
- } else {
- Some(attribute)
- }
- })
- .collect();
+ let mut i = || {
+ let attributes = Attribute::parse_outer(input)?
+ .into_iter()
+ .filter_map(|attribute| {
+ if attribute.path().is_ident("doc") {
+ doc.push(attribute);
+ None
+ } else {
+ Some(attribute)
+ }
+ })
+ .collect();
+ let visibility = input.parse()?;
- let visibility = input.parse()?;
- let i = || {
input
.peek(Token![::])
.then(|| {
@@ -182,7 +180,9 @@ impl Parse for StateMachineDef {
let g = input.parse::<Generics>()?;
Ok(ImplementationRequired::Yes(t, g))
})
+ .map(|x| (attributes, visibility, x))
};
+
let state_name = i()?;
input.parse::<Token![=>]>()?;
let input_name = i()?;
@@ -196,12 +196,10 @@ impl Parse for StateMachineDef {
Ok(Self {
doc,
- visibility,
state_name,
input_name,
output_name,
transitions,
- attributes,
})
}
}
diff --git a/rust-fsm/src/lib.rs b/rust-fsm/src/lib.rs
index ae43bcd..4f1bbaa 100644
--- a/rust-fsm/src/lib.rs
+++ b/rust-fsm/src/lib.rs
@@ -56,10 +56,13 @@ The DSL is parsed by the `state_machine` macro. Here is a little example.
use rust_fsm::*;
state_machine! {
- #[derive(Debug)]
- #[repr(C)]
+ #[derive(Debug)] #[repr(C)]
/// A Circuit Breaker state machine.
- CircuitBreaker => Result => Action
+ CircuitBreaker =>
+ #[derive(Debug)] #[repr(C)]
+ Result =>
+ #[derive(Debug)] #[repr(C)]
+ Action
Closed => Unsuccessful => Open [SetupTimer],
Open => TimerTriggered => HalfOpen,
diff --git a/rust-fsm/tests/circuit_breaker_dsl.rs b/rust-fsm/tests/circuit_breaker_dsl.rs
index 8d5e0f3..12da2cd 100644
--- a/rust-fsm/tests/circuit_breaker_dsl.rs
+++ b/rust-fsm/tests/circuit_breaker_dsl.rs
@@ -10,7 +10,9 @@ state_machine! {
/// capabilities of its library DSL for defining finite state machines.
/// https://martinfowler.com/bliki/CircuitBreaker.html
#[derive(Debug)]
- pub CircuitBreaker => Result => Action
+ pub CircuitBreaker =>
+ #[derive(Debug)] pub Result =>
+ #[derive(Debug)] pub Action
Closed => Unsuccessful => Open [SetupTimer],
Open => TimerTriggered => HalfOpen,
diff --git a/rust-fsm/tests/simple.rs b/rust-fsm/tests/simple.rs
index 3810dcf..b85440e 100644
--- a/rust-fsm/tests/simple.rs
+++ b/rust-fsm/tests/simple.rs
@@ -1,9 +1,7 @@
use rust_fsm::*;
state_machine! {
- #[derive(Debug)]
- #[repr(C)]
- Door => Action => __
+ #[derive(Debug)] #[repr(C)] Door => #[derive(Debug)] #[repr(C)] Action => __
Open => Key => Closed,
Closed => Key => Open,