Finite state machines in rust; bendns fork to add types.
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | README.md | 7 | ||||
| -rw-r--r-- | doc-example/Cargo.toml | 7 | ||||
| -rw-r--r-- | doc-example/src/lib.rs | 15 | ||||
| -rw-r--r-- | rust-fsm-dsl/src/lib.rs | 15 | ||||
| -rw-r--r-- | rust-fsm-dsl/src/parser.rs | 6 |
7 files changed, 46 insertions, 7 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e32578..fba31da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ adheres to [Semantic Versioning][semver]. generated inside the said module. * Supplying ones own enums for state, input and output in the proc-macro (#10). * An optional possibility to generate Mermaid diagrams. +* Processing doc comments to generate the state machine module documentation. ## [0.6.2] - 2024-05-11 ### Changed @@ -1,3 +1,3 @@ [workspace] resolver = "2" -members = ["rust-fsm", "rust-fsm-dsl"] +members = ["rust-fsm", "rust-fsm-dsl", "doc-example"] @@ -70,6 +70,7 @@ use rust_fsm::*; state_machine! { #[derive(Debug)] #[repr(C)] + /// A Circuit Breaker state machine. circuit_breaker(Closed) Closed(Unsuccessful) => Open [SetupTimer], @@ -198,6 +199,12 @@ 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. +To see this in action, download the repository and run: + +```bash +cargo doc -p doc-example --open +``` + ### Without DSL The `state_machine` macro has limited capabilities (for example, a state diff --git a/doc-example/Cargo.toml b/doc-example/Cargo.toml new file mode 100644 index 0000000..85693d0 --- /dev/null +++ b/doc-example/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "doc-example" +version = "0.1.0" +edition = "2021" + +[dependencies] +rust-fsm = { path = "../rust-fsm", version = "0.6.2", features = ["diagram"] } diff --git a/doc-example/src/lib.rs b/doc-example/src/lib.rs new file mode 100644 index 0000000..18c0978 --- /dev/null +++ b/doc-example/src/lib.rs @@ -0,0 +1,15 @@ +use rust_fsm::state_machine; + +state_machine! { + /// A dummy implementation of the Circuit Breaker pattern to demonstrate + /// capabilities of its library DSL for defining finite state machines. + /// https://martinfowler.com/bliki/CircuitBreaker.html + pub circuit_breaker(Closed) + + Closed(Unsuccessful) => Open [SetupTimer], + Open(TimerTriggered) => HalfOpen, + HalfOpen => { + Successful => Closed, + Unsuccessful => Open [SetupTimer] + } +} diff --git a/rust-fsm-dsl/src/lib.rs b/rust-fsm-dsl/src/lib.rs index cc11d31..ea0400e 100644 --- a/rust-fsm-dsl/src/lib.rs +++ b/rust-fsm-dsl/src/lib.rs @@ -7,7 +7,7 @@ extern crate proc_macro; use proc_macro::TokenStream; use quote::{quote, ToTokens}; use std::{collections::BTreeSet, iter::FromIterator}; -use syn::{parse_macro_input, Ident}; +use syn::{parse_macro_input, Attribute, Ident}; mod parser; @@ -20,17 +20,19 @@ struct Transition<'a> { output: &'a Option<Ident>, } +fn attrs_to_token_stream(attrs: Vec<Attribute>) -> proc_macro2::TokenStream { + let attrs = attrs.into_iter().map(ToTokens::into_token_stream); + proc_macro2::TokenStream::from_iter(attrs) +} + #[proc_macro] /// Produce a state machine definition from the provided `rust-fmt` DSL /// description. pub fn state_machine(tokens: TokenStream) -> TokenStream { let input = parse_macro_input!(tokens as parser::StateMachineDef); - let attrs = input - .attributes - .into_iter() - .map(ToTokens::into_token_stream); - let attrs = proc_macro2::TokenStream::from_iter(attrs); + let doc = attrs_to_token_stream(input.doc); + let attrs = attrs_to_token_stream(input.attributes); if input.transitions.is_empty() { let output = quote! { @@ -171,6 +173,7 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream { let diagram = quote!(); let output = quote! { + #doc #diagram #visibility mod #fsm_name { #attrs diff --git a/rust-fsm-dsl/src/parser.rs b/rust-fsm-dsl/src/parser.rs index 7b97a03..d4a9c2e 100644 --- a/rust-fsm-dsl/src/parser.rs +++ b/rust-fsm-dsl/src/parser.rs @@ -116,6 +116,7 @@ impl Parse for TransitionDef { /// } /// ``` pub struct StateMachineDef { + pub doc: Vec<Attribute>, /// The visibility modifier (applies to all generated items) pub visibility: Visibility, pub name: Ident, @@ -130,12 +131,16 @@ pub struct StateMachineDef { impl Parse for StateMachineDef { fn parse(input: ParseStream) -> Result<Self> { let mut state_machine_attributes = Vec::new(); + let mut doc = Vec::new(); let attributes = Attribute::parse_outer(input)? .into_iter() .filter_map(|attribute| { if attribute.path().is_ident("state_machine") { state_machine_attributes.push(attribute); None + } else if attribute.path().is_ident("doc") { + doc.push(attribute); + None } else { Some(attribute) } @@ -177,6 +182,7 @@ impl Parse for StateMachineDef { .collect(); Ok(Self { + doc, visibility, name, initial_state, |