Finite state machines in rust; bendns fork to add types.
Merge pull request #8 from jost-aaron/feature/repr_c
Co-authored-by: Aaron Jost <[email protected]>
| -rw-r--r-- | README.md | 3 | ||||
| -rw-r--r-- | rust-fsm-dsl/src/lib.rs | 10 | ||||
| -rw-r--r-- | rust-fsm-dsl/src/parser.rs | 32 | ||||
| -rw-r--r-- | rust-fsm/tests/simple.rs | 1 |
4 files changed, 46 insertions, 0 deletions
@@ -57,6 +57,7 @@ use rust_fsm::*; state_machine! { derive(Debug) + repr_c(true) CircuitBreaker(Closed) Closed(Unsuccessful) => Open [SetupTimer], @@ -72,6 +73,8 @@ This code sample: * Defines a state machine called `CircuitBreaker`; * Derives the `Debug` trait for it (the `derive` section is optional); +* Adds repr(C) support to generated code for better FFI compatability + (the `repr_c` section is optional and defaults to false); * Sets the initial state of this state machine to `Closed`; * Defines state transitions. For example: on receiving the `Successful` input when in the `HalfOpen` state, the machine must move to the `Closed` diff --git a/rust-fsm-dsl/src/lib.rs b/rust-fsm-dsl/src/lib.rs index 690dbc6..ba4ef46 100644 --- a/rust-fsm-dsl/src/lib.rs +++ b/rust-fsm-dsl/src/lib.rs @@ -32,6 +32,12 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream { quote! {} }; + let type_repr = if let Some(true) = input.repr_c { + quote! { #[repr(C)] } + } else { + quote! {} + }; + if input.transitions.is_empty() { let output = quote! { compile_error!("rust-fsm: at least one state transition must be provided"); @@ -91,6 +97,7 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream { 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),* } @@ -125,14 +132,17 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream { let output = quote! { #derives + #type_repr #visibility struct #struct_name; #derives + #type_repr #visibility enum #states_enum_name { #(#states),* } #derives + #type_repr #visibility enum #inputs_enum_name { #(#inputs),* } diff --git a/rust-fsm-dsl/src/parser.rs b/rust-fsm-dsl/src/parser.rs index 25a1283..7ea732d 100644 --- a/rust-fsm-dsl/src/parser.rs +++ b/rust-fsm-dsl/src/parser.rs @@ -7,6 +7,7 @@ use syn::{ mod kw { syn::custom_keyword!(derive); + syn::custom_keyword!(repr_c); } /// The output of a state transition @@ -105,6 +106,34 @@ impl Parse for TransitionDef { } } + +struct ReprC { + repr_c: Option<bool>, +} + +impl Parse for ReprC { + fn parse(input: ParseStream) -> Result<Self> { + let lookahead = input.lookahead1(); + if lookahead.peek(kw::repr_c) { + let kw_repr_c = input.parse::<kw::repr_c>()?; + let entries_content; + parenthesized!(entries_content in input); + match entries_content.parse::<syn::Lit>() { + Ok(syn::Lit::Bool(b)) => { + return Ok( ReprC { + repr_c: Some(b.value()), + }); + }, + _ => { + return Err(Error::new_spanned(kw_repr_c, "Invalid repr_c argument")); + }, + } + } + Ok(ReprC { repr_c: None }) + } +} + + struct Derives { derives: Option<Vec<Ident>>, } @@ -152,11 +181,13 @@ pub struct StateMachineDef { pub initial_state: Ident, pub transitions: Vec<TransitionDef>, pub derives: Option<Vec<Ident>>, + pub repr_c: Option<bool>, } impl Parse for StateMachineDef { fn parse(input: ParseStream) -> Result<Self> { let Derives { derives } = input.parse()?; + let ReprC { repr_c } = input.parse()?; let visibility = input.parse()?; let name = input.parse()?; @@ -176,6 +207,7 @@ impl Parse for StateMachineDef { initial_state, transitions, derives, + repr_c, }) } } diff --git a/rust-fsm/tests/simple.rs b/rust-fsm/tests/simple.rs index b3fa09c..d889dbb 100644 --- a/rust-fsm/tests/simple.rs +++ b/rust-fsm/tests/simple.rs @@ -2,6 +2,7 @@ use rust_fsm::*; state_machine! { derive(Debug) + repr_c(true) Door(Open) Open(Key) => Closed, |