Finite state machines in rust; bendns fork to add types.
-rw-r--r--rust-fsm-dsl/src/lib.rs5
-rw-r--r--rust-fsm-dsl/src/parser.rs1
-rw-r--r--rust-fsm/src/lib.rs60
3 files changed, 25 insertions, 41 deletions
diff --git a/rust-fsm-dsl/src/lib.rs b/rust-fsm-dsl/src/lib.rs
index d73e0a2..1c9fe36 100644
--- a/rust-fsm-dsl/src/lib.rs
+++ b/rust-fsm-dsl/src/lib.rs
@@ -189,6 +189,7 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
})
});
let state_name = state_name.path();
+ let output_generics = output_name.g();
let output_impl = variant::tokenize(&outputs, |outputs| {
output_name.tokenize(|output_name| {
// Many attrs and derives may work incorrectly (or simply not work) for empty enums, so we just skip them
@@ -201,7 +202,7 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
quote! {
#attrs
- #visibility enum #output_name {
+ #visibility enum #output_name #output_generics {
#(#outputs),*
}
}
@@ -227,7 +228,7 @@ pub fn state_machine(tokens: TokenStream) -> TokenStream {
impl ::rust_fsm::StateMachine for #state_name {
type Input<'i> = #input_name #input_generics;
- type Output<'o> = #output_name;
+ type Output<'i> = #output_name #output_generics;
fn transition(self, input: Self::Input<'_>) -> ::core::result::Result<
(Self, ::core::option::Option<Self::Output<'_>>),
diff --git a/rust-fsm-dsl/src/parser.rs b/rust-fsm-dsl/src/parser.rs
index 869772d..7a25efe 100644
--- a/rust-fsm-dsl/src/parser.rs
+++ b/rust-fsm-dsl/src/parser.rs
@@ -180,7 +180,6 @@ impl Parse for StateMachineDef {
.unwrap_or_else(|| {
let t = input.parse::<Ident>()?;
let g = input.parse::<Generics>()?;
- dbg!(&g);
Ok(ImplementationRequired::Yes(t, g))
})
};
diff --git a/rust-fsm/src/lib.rs b/rust-fsm/src/lib.rs
index 0dd44fc..ae43bcd 100644
--- a/rust-fsm/src/lib.rs
+++ b/rust-fsm/src/lib.rs
@@ -231,36 +231,32 @@ pub trait StateMachine: Sized {
/// The input alphabet.
type Input<'i>;
/// The output alphabet.
- type Output<'o>;
+ type Output<'i>;
/// The transition fuction that outputs a new state based on the current
/// state and the provided input. Outputs [`Err`] (allowing recovery of the state and input)
/// when there is no transition for a given combination of the input and the state.
/// Also gives you the output, if any.
///
/// This function is discouraged from panicking.
- fn transition(
+ fn transition<'i>(
self,
- input: Self::Input<'_>,
- ) -> Result<(Self, Option<Self::Output<'_>>), TransitionImpossibleError<Self, Self::Input<'_>>>;
+ input: Self::Input<'i>,
+ ) -> Result<(Self, Option<Self::Output<'i>>), TransitionImpossibleError<Self, Self::Input<'i>>>;
/// Consumes the provided input, gives an output and performs a state
/// transition. If a state transition with the current state and the
/// provided input is not allowed, returns an error containing the input.
///
/// Aborts if `transition` panics.
- fn consume<'l>(
- &mut self,
- input: Self::Input<'l>,
- ) -> Result<Option<Self::Output<'l>>, TransitionImpossibleError_<Self, Self::Input<'l>>> {
+ fn consume<'me, 'i>(
+ &'me mut self,
+ input: Self::Input<'i>,
+ ) -> Result<Option<Self::Output<'i>>, TransitionImpossibleError_<'me, Self, Self::Input<'i>>>
+ {
replace_with_or_abort_and_return(self, |x| match x.transition(input) {
Ok((state, ret)) => (Ok(ret), state),
- Err(TransitionImpossibleError { state, input }) => (
- Err(TransitionImpossibleError_ {
- state: PhantomData,
- input,
- }),
- state,
- ),
+ Err(TransitionImpossibleError { state, input }) => (Err(input), state),
})
+ .map_err(|input| TransitionImpossibleError_ { state: self, input })
}
}
@@ -271,13 +267,17 @@ pub struct TransitionImpossibleError<S, I> {
pub state: S,
pub input: I,
}
+/// An error type that represents that the state transition is impossible given
+/// the current combination of state and input.
#[derive(Debug, Clone)]
-pub struct TransitionImpossibleError_<S, I> {
- pub state: PhantomData<S>,
+pub struct TransitionImpossibleError_<'a, S, I> {
+ pub state: &'a S,
pub input: I,
}
+macro_rules! implement {
+ ({$($p:tt)+} $ty:ty) => {
-impl<S: Debug, I: Debug> fmt::Display for TransitionImpossibleError<S, I> {
+impl<$($p)+> fmt::Display for $ty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
@@ -287,27 +287,11 @@ impl<S: Debug, I: Debug> fmt::Display for TransitionImpossibleError<S, I> {
)
}
}
-impl<S: Debug, I: Debug> fmt::Display for TransitionImpossibleError_<S, I> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(
- f,
- "cannot perform a state transition from the current state (of type {:?}) with the provided input ({:?})",
- self.state,
- self.input
- )
- }
-}
-
#[cfg(feature = "std")]
-impl<S: Debug, I: Debug> Error for TransitionImpossibleError<S, I> {
+impl<$($p)+> Error for $ty {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
-}
-
-#[cfg(feature = "std")]
-impl<S: Debug, I: Debug> Error for TransitionImpossibleError_<S, I> {
- fn source(&self) -> Option<&(dyn Error + 'static)> {
- None
- }
-}
+}}}
+implement!({S: Debug, I: Debug} TransitionImpossibleError<S, I>);
+implement!({'a, S: Debug, I: Debug} TransitionImpossibleError_<'a, S, I>);