Finite state machines in rust; bendns fork to add types.
| -rw-r--r-- | rust-fsm-dsl/src/lib.rs | 25 | ||||
| -rw-r--r-- | rust-fsm-dsl/src/variant.rs | 27 | ||||
| -rw-r--r-- | rust-fsm/src/lib.rs | 6 |
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. |