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.rs120
1 files changed, 57 insertions, 63 deletions
diff --git a/rust-fsm-dsl/src/lib.rs b/rust-fsm-dsl/src/lib.rs
index ba4ef46..3d82364 100644
--- a/rust-fsm-dsl/src/lib.rs
+++ b/rust-fsm-dsl/src/lib.rs
@@ -45,7 +45,7 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
return output.into();
}
- let struct_name = input.name;
+ let fsm_name = input.name;
let visibility = input.visibility;
let transitions: Vec<_> = input
@@ -76,94 +76,88 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
}
}
- let states_enum_name = Ident::new(&format!("{}State", struct_name), struct_name.span());
let initial_state_name = &input.initial_state;
- let inputs_enum_name = Ident::new(&format!("{}Input", struct_name), struct_name.span());
-
let mut transition_cases = vec![];
for transition in transitions.iter() {
let initial_state = &transition.initial_state;
let input_value = &transition.input_value;
let final_state = &transition.final_state;
transition_cases.push(quote! {
- (#states_enum_name::#initial_state, #inputs_enum_name::#input_value) => {
- Some(#states_enum_name::#final_state)
+ (State::#initial_state, Input::#input_value) => {
+ Some(State::#final_state)
}
});
}
- let (outputs_repr, outputs_type, output_impl) = if !outputs.is_empty() {
- let outputs_type_name = Ident::new(&format!("{}Output", struct_name), struct_name.span());
- let outputs_repr = quote! {
- #derives
- #type_repr
- #visibility enum #outputs_type_name {
- #(#outputs),*
- }
- };
-
- let outputs_type = quote! { #outputs_type_name };
-
- let mut output_cases = vec![];
- for transition in transitions.iter() {
- if let Some(output_value) = &transition.output {
- let initial_state = &transition.initial_state;
- let input_value = &transition.input_value;
- output_cases.push(quote! {
- (#states_enum_name::#initial_state, #inputs_enum_name::#input_value) => {
- Some(#outputs_type_name::#output_value)
- }
- });
- }
+ let mut output_cases = vec![];
+ for transition in transitions.iter() {
+ if let Some(output_value) = &transition.output {
+ let initial_state = &transition.initial_state;
+ let input_value = &transition.input_value;
+ output_cases.push(quote! {
+ (State::#initial_state, Input::#input_value) => {
+ Some(Output::#output_value)
+ }
+ });
}
+ }
- let output_impl = quote! {
- match (state, input) {
- #(#output_cases)*
- _ => None,
- }
- };
+ let attrs = quote! {
+ #derives
+ #type_repr
+ };
- (outputs_repr, outputs_type, output_impl)
+ // 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 output_attrs = if outputs.is_empty() {
+ quote!()
} else {
- (quote! {}, quote! { () }, quote! {None})
+ attrs.clone()
};
let output = quote! {
- #derives
- #type_repr
- #visibility struct #struct_name;
+ #visibility mod #fsm_name {
+ #attrs
+ pub struct Impl;
- #derives
- #type_repr
- #visibility enum #states_enum_name {
- #(#states),*
- }
+ pub type StateMachine = rust_fsm::StateMachine<Impl>;
- #derives
- #type_repr
- #visibility enum #inputs_enum_name {
- #(#inputs),*
- }
+ #attrs
+ pub enum Input {
+ #(#inputs),*
+ }
- #outputs_repr
+ #attrs
+ pub enum State {
+ #(#states),*
+ }
+
+ #output_attrs
+ pub enum Output {
+ #(#outputs),*
+ }
- impl rust_fsm::StateMachineImpl for #struct_name {
- type Input = #inputs_enum_name;
- type State = #states_enum_name;
- type Output = #outputs_type;
- const INITIAL_STATE: Self::State = #states_enum_name::#initial_state_name;
+ impl rust_fsm::StateMachineImpl for Impl {
+ type Input = Input;
+ type State = State;
+ type Output = Output;
+ const INITIAL_STATE: Self::State = State::#initial_state_name;
- fn transition(state: &Self::State, input: &Self::Input) -> Option<Self::State> {
- match (state, input) {
- #(#transition_cases)*
- _ => None,
+ fn transition(state: &Self::State, input: &Self::Input) -> Option<Self::State> {
+ match (state, input) {
+ #(#transition_cases)*
+ _ => None,
+ }
}
- }
- fn output(state: &Self::State, input: &Self::Input) -> Option<Self::Output> {
- #output_impl
+ fn output(state: &Self::State, input: &Self::Input) -> Option<Self::Output> {
+ match (state, input) {
+ #(#output_cases)*
+ _ => None,
+ }
+ }
}
}
};