Finite state machines in rust; bendns fork to add types.
ogen
| -rw-r--r-- | rust-fsm-dsl/src/lib.rs | 5 | ||||
| -rw-r--r-- | rust-fsm-dsl/src/parser.rs | 1 | ||||
| -rw-r--r-- | rust-fsm/src/lib.rs | 60 |
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>); |