Finite state machines in rust; bendns fork to add types.
-rw-r--r--README.md3
-rw-r--r--rust-fsm-dsl/src/lib.rs10
-rw-r--r--rust-fsm-dsl/src/parser.rs32
-rw-r--r--rust-fsm/tests/simple.rs1
4 files changed, 46 insertions, 0 deletions
diff --git a/README.md b/README.md
index f55746e..8faaa5b 100644
--- a/README.md
+++ b/README.md
@@ -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,