Finite state machines in rust; bendns fork to add types.
Diffstat (limited to 'rust-fsm-dsl/src/lib.rs')
-rw-r--r--rust-fsm-dsl/src/lib.rs100
1 files changed, 58 insertions, 42 deletions
diff --git a/rust-fsm-dsl/src/lib.rs b/rust-fsm-dsl/src/lib.rs
index df39b74..55385ca 100644
--- a/rust-fsm-dsl/src/lib.rs
+++ b/rust-fsm-dsl/src/lib.rs
@@ -6,7 +6,7 @@ extern crate proc_macro;
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
-use std::{collections::BTreeSet, iter::FromIterator};
+use std::iter::FromIterator;
use syn::*;
mod parser;
mod variant;
@@ -63,15 +63,17 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
// use std::hash::BuildHasher;
// rustc_hash::FxSeededState::with_seed(5).hash_one(x)
// }
- let mut states = BTreeSet::new();
- let mut inputs = BTreeSet::new();
- let mut outputs = BTreeSet::new();
- let mut transition_cases = Vec::new();
- let mut output_cases = Vec::new();
+ let mut states = vec![];
+ let mut inputs = vec![];
+ let mut outputs = vec![];
+ let mut transition_cases = vec![];
+ let mut output_cases = vec![];
- use std::fmt::Write;
#[cfg(feature = "diagram")]
- let mut mermaid_diagram = format!("///```mermaid\n///stateDiagram-v2\n",);
+ let mut mermaid_diagram = format!(
+ "///```mermaid
+///stateDiagram-v2\n",
+ );
for transition in transitions {
let Transition {
initial_state,
@@ -94,11 +96,19 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
// id(&final_state)
// )
// .unwrap();
+ use std::fmt::Write;
#[cfg(feature = "diagram")]
write!(
mermaid_diagram,
- "/// {initial_state} --> {final_state}: {}",
- input_value.match_on()
+ "/// {}",
+ &format!(
+ "{:?}",
+ format!(
+ "{initial_state} --> {final_state}: {}",
+ input_value.match_on()
+ )
+ )
+ .trim_matches('"'),
)
.unwrap();
@@ -129,11 +139,11 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
#[cfg(feature = "diagram")]
mermaid_diagram.push('\n');
- states.insert(initial_state);
- states.insert(Box::leak(Box::new(final_state.clone().variant())));
- inputs.insert(input_value);
- if let Some(ref output) = output {
- outputs.insert(output);
+ states.push(initial_state.clone());
+ states.push(final_state.clone().variant());
+ inputs.push(input_value.clone());
+ if let Some(output) = output {
+ outputs.push(output.clone().variant());
}
}
@@ -146,44 +156,50 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
.replace(')', "#41;")
.replace('[', "#91;")
.replace(']', "#93;")
+ .replace('|', "#124;")
.replace("Default", "def")
.parse()
.unwrap();
- let input_impl = input_name.tokenize(|f| {
- quote! {
- #attrs
- #visibility enum #f {
- #(#inputs),*
+ let input_impl = variant::tokenize(&inputs, |x| {
+ input_name.tokenize(|f| {
+ quote! {
+ #attrs
+ #visibility enum #f {
+ #(#x),*
+ }
}
- }
+ })
});
let input_name = input_name.path();
- let state_impl = state_name.tokenize(|f| {
- quote! {
- #attrs
- #visibility enum #f {
- #(#states),*
+ let state_impl = variant::tokenize(&states, |x| {
+ state_name.tokenize(|f| {
+ quote! {
+ #attrs
+ #visibility enum #f {
+ #(#x),*
+ }
}
- }
+ })
});
let state_name = state_name.path();
-
- let output_impl = 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 {
- #(#outputs),*
+ let output_impl = variant::tokenize(&*outputs, |outputs| {
+ 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 {
+ #(#outputs),*
+ }
}
- }
+ })
});
let output_name = output_name.path();