Finite state machines in rust; bendns fork to add types.
bendn 5 weeks ago
parent 16afc8e · commit cb6952f
-rw-r--r--rust-fsm-dsl/src/lib.rs25
-rw-r--r--rust-fsm-dsl/src/variant.rs27
-rw-r--r--rust-fsm/src/lib.rs6
3 files changed, 40 insertions, 18 deletions
diff --git a/rust-fsm-dsl/src/lib.rs b/rust-fsm-dsl/src/lib.rs
index 094e3b2..47e55f1 100644
--- a/rust-fsm-dsl/src/lib.rs
+++ b/rust-fsm-dsl/src/lib.rs
@@ -164,7 +164,7 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
.parse()
.unwrap();
let input_generics = input_name.g();
- let input_impl = variant::tokenize(&inputs, |x| {
+ let input_impl = variant::tokenize(&inputs, |x, matcher| {
let attrs = attrs_to_token_stream(input_attrs);
input_name.tokenize(|f| {
quote! {
@@ -172,11 +172,17 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
#input_visibility enum #f #input_generics {
#(#x),*
}
+
+ impl #input_generics #f #input_generics {
+ #input_visibility fn name(&self) -> &'static str {
+ match self { #(Self::#matcher => stringify!(#x)),* }
+ }
+ }
}
})
});
let input_name = input_name.path();
- let state_impl = variant::tokenize(&states, |x| {
+ let state_impl = variant::tokenize(&states, |x, matcher| {
let attrs = attrs_to_token_stream(state_attrs.clone());
state_name.tokenize(|f| {
quote! {
@@ -184,12 +190,18 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
#state_visibility enum #f {
#(#x),*
}
+
+ impl #f {
+ #state_visibility fn name(&self) -> &'static str {
+ match self { #(Self::#matcher => stringify!(#x)),* }
+ }
+ }
}
})
});
let state_name = state_name.path();
let output_generics = output_name.g();
- let output_impl = variant::tokenize(&outputs, |outputs| {
+ let output_impl = variant::tokenize(&outputs, |outputs, matcher| {
let attrs = attrs_to_token_stream(output_attrs);
output_name.tokenize(|output_name| {
quote! {
@@ -197,6 +209,12 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
#output_visibility enum #output_name #output_generics {
#(#outputs),*
}
+
+ impl #output_generics #output_name #output_generics {
+ #output_visibility fn name(&self) -> &'static str {
+ match self { #(Self::#matcher => stringify!(#outputs)),* }
+ }
+ }
}
})
});
@@ -231,7 +249,6 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
(state, input) => ::core::result::Result::Err(::rust_fsm::TransitionImpossibleError { state, input, }),
}
}
-
}
};
diff --git a/rust-fsm-dsl/src/variant.rs b/rust-fsm-dsl/src/variant.rs
index b4373a8..740da8f 100644
--- a/rust-fsm-dsl/src/variant.rs
+++ b/rust-fsm-dsl/src/variant.rs
@@ -22,24 +22,29 @@ pub fn find_type(of: &Variant, list: &[Variant]) -> Option<Type> {
}
pub fn tokenize(
inputs: &[Variant],
- f: impl FnOnce(Vec<TokenStream>) -> TokenStream,
+ f: impl FnOnce(Vec<TokenStream>, Vec<TokenStream>) -> TokenStream,
) -> TokenStream {
let (Ok(x) | Err(x)) = BTreeSet::from_iter(inputs)
.into_iter()
.map(|x| {
let i = &x.ident;
- x.field.as_ref().map_or(Ok(quote! { #i }), |_| {
- let y = find_type(x, inputs);
- y.ok_or(Error::new_spanned(&x.ident, "type never specified"))
- .map(|y| match y {
- Type::Tuple(TypeTuple { elems, .. }) => quote! { #i(#elems) },
- y => quote! {#i(#y)},
- })
- })
+ x.field
+ .as_ref()
+ .map_or(Ok((quote! { #i }, quote! { #i })), |_| {
+ let y = find_type(x, inputs);
+ y.ok_or(Error::new_spanned(&x.ident, "type never specified"))
+ .map(|y| match y {
+ Type::Tuple(TypeTuple { elems, .. }) => {
+ let x = elems.iter().map(|_| quote! { _ });
+ (quote! { #i(#elems) }, quote! { #i(#(#x),* )})
+ }
+ y => (quote! {#i(#y)}, quote! {#i(_)}),
+ })
+ })
})
- .collect::<Result<_>>()
+ .collect::<Result<(Vec<_>, Vec<_>)>>()
.map_err(Error::into_compile_error)
- .map(f);
+ .map(|(a, b)| f(a, b));
x
}
diff --git a/rust-fsm/src/lib.rs b/rust-fsm/src/lib.rs
index 4f1bbaa..22e4fa6 100644
--- a/rust-fsm/src/lib.rs
+++ b/rust-fsm/src/lib.rs
@@ -124,7 +124,7 @@ You can specify visibility like this:
use rust_fsm::*;
state_machine! {
- pub CircuitBreaker => Result => Action
+ pub CircuitBreaker => pub Result => pub Action
Closed => Unsuccessful => Open [SetupTimer],
Open => TimerTriggered => HalfOpen,
@@ -176,8 +176,8 @@ state_machine! {
#### Diagrams
-`state_machine` macro can document your state machines with diagrams. This is
-controlled by the `diagram` feature, which is non-default. The diagrams are
+`state_machi`ne` macro can document your state machines with diagrams. This is
+controlled by` the `diagram` feature, which is non-default. The diagrams are
generated in the [Mermaid][mermaid] format. This feature includes the Mermaid
script into the documentation page.