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.rs82
1 files changed, 52 insertions, 30 deletions
diff --git a/rust-fsm-dsl/src/lib.rs b/rust-fsm-dsl/src/lib.rs
index 621402e..df39b74 100644
--- a/rust-fsm-dsl/src/lib.rs
+++ b/rust-fsm-dsl/src/lib.rs
@@ -12,14 +12,14 @@ mod parser;
mod variant;
use variant::Variant;
-use crate::parser::StateMachineDef;
+use crate::{parser::StateMachineDef, variant::Final};
/// The full information about a state transition. Used to unify the
/// represantion of the simple and the compact forms.
struct Transition<'a> {
initial_state: &'a Variant,
input_value: &'a Variant,
- final_state: &'a Variant,
- output: &'a Option<Variant>,
+ final_state: &'a Final,
+ output: &'a Option<Final>,
}
fn attrs_to_token_stream(attrs: Vec<Attribute>) -> proc_macro2::TokenStream {
@@ -37,7 +37,6 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
state_name,
input_name,
output_name,
- initial_state,
transitions,
attributes,
} = parse_macro_input!(tokens as parser::StateMachineDef);
@@ -60,21 +59,19 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
output: &transition.output,
})
});
-
+ // fn id(x: impl std::hash::Hash) -> u64 {
+ // 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();
+ use std::fmt::Write;
#[cfg(feature = "diagram")]
- let mut mermaid_diagram = format!(
- "///```mermaid\n///stateDiagram-v2\n/// [*] --> {}\n",
- initial_state
- );
-
- states.insert(&initial_state);
-
+ let mut mermaid_diagram = format!("///```mermaid\n///stateDiagram-v2\n",);
for transition in transitions {
let Transition {
initial_state,
@@ -83,36 +80,57 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
output,
} = transition;
+ // #[cfg(feature = "diagram")]
+ // writeln!(
+ // mermaid_diagram,
+ // "/// {}: {initial_state}",
+ // id(&initial_state)
+ // )
+ // .unwrap();
+ // #[cfg(feature = "diagram")]
+ // writeln!(
+ // mermaid_diagram,
+ // "/// {}: {final_state}",
+ // id(&final_state)
+ // )
+ // .unwrap();
#[cfg(feature = "diagram")]
- mermaid_diagram.push_str(&format!(
- "/// {initial_state} --> {final_state}: {input_value}"
- ));
-
- let input_ = input_value.match_on();
- let final_state_ = final_state.match_on();
+ write!(
+ mermaid_diagram,
+ "/// {initial_state} --> {final_state}: {}",
+ input_value.match_on()
+ )
+ .unwrap();
+
+ let initial_ = initial_state.match_on();
+ let final_ = final_state.reduce();
+ let (input_, guard) = input_value.separate();
+
+ // let input_ = input_value.match_on();
+ // let final_state_ = final_state.match_on();
transition_cases.push(quote! {
- (Self::#initial_state, Self::Input::#input_) => {
- Some(Self::#final_state_)
+ (Self::#initial_, Self::Input::#input_) #guard => {
+ Some(Self::#final_)
}
});
if let Some(output_value) = output {
- let output_value_ = output_value.match_on();
+ let output_ = output_value.reduce();
output_cases.push(quote! {
- (Self::#initial_state, Self::Input::#input_) => {
- Some(Self::Output::#output_value_)
+ (Self::#initial_, Self::Input::#input_) #guard => {
+ Some(Self::Output::#output_)
}
});
#[cfg(feature = "diagram")]
- mermaid_diagram.push_str(&format!(" [{output_value}]"));
+ mermaid_diagram.push_str(&format!(" [\"{output_value}\"]"));
}
#[cfg(feature = "diagram")]
mermaid_diagram.push('\n');
states.insert(initial_state);
- states.insert(final_state);
+ states.insert(Box::leak(Box::new(final_state.clone().variant())));
inputs.insert(input_value);
if let Some(ref output) = output {
outputs.insert(output);
@@ -122,9 +140,15 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
#[cfg(feature = "diagram")]
mermaid_diagram.push_str("///```");
#[cfg(feature = "diagram")]
- let mermaid_diagram: proc_macro2::TokenStream = mermaid_diagram.parse().unwrap();
-
- let initial_state_name = &initial_state;
+ let mermaid_diagram: proc_macro2::TokenStream = mermaid_diagram
+ .replace("::", "#58;#58;")
+ .replace('(', "#40;")
+ .replace(')', "#41;")
+ .replace('[', "#91;")
+ .replace(']', "#93;")
+ .replace("Default", "def")
+ .parse()
+ .unwrap();
let input_impl = input_name.tokenize(|f| {
quote! {
@@ -172,7 +196,6 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
#[cfg(not(feature = "diagram"))]
let diagram = quote!();
-
let output = quote! {
#input_impl
#doc
@@ -183,7 +206,6 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
impl ::rust_fsm::StateMachineImpl for #state_name {
type Input = #input_name;
type Output = #output_name;
- const INITIAL_STATE: Self = Self::#initial_state_name;
fn transition(self, input: Self::Input) -> Option<Self> {
match (self, input) {