diff --git a/fsm/Cargo.toml b/fsm/Cargo.toml index 4f42ae438..370ea23dc 100644 --- a/fsm/Cargo.toml +++ b/fsm/Cargo.toml @@ -4,10 +4,6 @@ version = "0.1.0" authors = ["Spencer Judge "] edition = "2018" -[[test]] -name = "card_reader" -path = "tests/card_reader.rs" - [dependencies] thiserror = "1.0" derive_more = "0.99" diff --git a/fsm/state_machine_procmacro/src/lib.rs b/fsm/state_machine_procmacro/src/lib.rs index ae59346c8..d7dbc9d48 100644 --- a/fsm/state_machine_procmacro/src/lib.rs +++ b/fsm/state_machine_procmacro/src/lib.rs @@ -9,7 +9,7 @@ use syn::{ parse_macro_input, punctuated::Punctuated, spanned::Spanned, - Error, Fields, Ident, Token, Variant, + Error, Fields, Ident, Token, Type, Variant, }; /// Parses a DSL for defining finite state machines, and produces code implementing the @@ -23,7 +23,7 @@ use syn::{ /// use state_machine_trait::{StateMachine, TransitionResult}; /// /// fsm! { -/// CardReader, Commands, Infallible +/// name CardReader; command Commands; error Infallible; shared_state CardId; /// /// Locked --(CardReadable(CardData), on_card_readable) --> ReadingCard; /// ReadingCard --(CardAccepted, on_card_accepted) --> DoorOpen; @@ -31,6 +31,11 @@ use syn::{ /// DoorOpen --(DoorClosed, on_door_closed) --> Locked; /// } /// +/// #[derive(Clone)] +/// pub struct CardId { +/// some_id: String +/// } +/// /// #[derive(Debug, Clone, Eq, PartialEq, Hash)] /// pub enum Commands { /// StartBlinkingLight, @@ -80,24 +85,24 @@ use syn::{ /// } /// } /// -/// let cr = CardReader::Locked(Locked {}); -/// let (cr, cmds) = cr -/// .on_event(CardReaderEvents::CardReadable("badguy".to_string())) -/// .unwrap(); +/// # fn main() -> Result<(), Box> { +/// let crs = CardReaderState::Locked(Locked {}); +/// let mut cr = CardReader { state: crs, shared_state: CardId { some_id: "an_id!".to_string() } }; +/// let cmds = cr.on_event_mut(CardReaderEvents::CardReadable("badguy".to_string()))?; /// assert_eq!(cmds[0], Commands::ProcessData("badguy".to_string())); /// assert_eq!(cmds[1], Commands::StartBlinkingLight); /// -/// let (cr, cmds) = cr.on_event(CardReaderEvents::CardRejected).unwrap(); +/// let cmds = cr.on_event_mut(CardReaderEvents::CardRejected)?; /// assert_eq!(cmds[0], Commands::StopBlinkingLight); /// -/// let (cr, cmds) = cr -/// .on_event(CardReaderEvents::CardReadable("goodguy".to_string())) -/// .unwrap(); +/// let cmds = cr.on_event_mut(CardReaderEvents::CardReadable("goodguy".to_string()))?; /// assert_eq!(cmds[0], Commands::ProcessData("goodguy".to_string())); /// assert_eq!(cmds[1], Commands::StartBlinkingLight); /// -/// let (_, cmds) = cr.on_event(CardReaderEvents::CardAccepted).unwrap(); +/// let cmds = cr.on_event_mut(CardReaderEvents::CardAccepted)?; /// assert_eq!(cmds[0], Commands::StopBlinkingLight); +/// # Ok(()) +/// # } /// ``` /// /// In the above example the first word is the name of the state machine, then after the comma the @@ -116,9 +121,16 @@ use syn::{ /// the `ReadingCard` state. /// /// The macro will generate a few things: -/// * An enum with a variant for each state, named with the provided name. In this case: +/// * A struct for the overall state machine, named with the provided name. Here: +/// ```ignore +/// struct CardMachine { +/// state: CardMachineState, +/// shared_state: CardId, +/// } +/// ``` +/// * An enum with a variant for each state, named with the provided name + "State". /// ```ignore -/// enum CardMachine { +/// enum CardMachineState { /// Locked(Locked), /// ReadingCard(ReadingCard), /// Unlocked(Unlocked), @@ -128,7 +140,7 @@ use syn::{ /// You are expected to define a type for each state, to contain that state's data. If there is /// no data, you can simply: `type StateName = ()` /// * An enum with a variant for each event. You are expected to define the type (if any) contained -/// in the event variant. In this case: +/// in the event variant. /// ```ignore /// enum CardMachineEvents { /// CardReadable(CardData) @@ -145,8 +157,16 @@ pub fn fsm(input: TokenStream) -> TokenStream { def.codegen() } +mod kw { + syn::custom_keyword!(name); + syn::custom_keyword!(command); + syn::custom_keyword!(error); + syn::custom_keyword!(shared_state); +} + struct StateMachineDefinition { name: Ident, + shared_state_type: Option, command_type: Ident, error_type: Ident, transitions: HashSet, @@ -156,10 +176,10 @@ impl Parse for StateMachineDefinition { // TODO: Pub keyword fn parse(input: ParseStream) -> Result { // First parse the state machine name, command type, and error type - let (name, command_type, error_type) = parse_first_line(&input).map_err(|mut e| { + let (name, command_type, error_type, shared_state_type) = parse_machine_types(&input).map_err(|mut e| { e.combine(Error::new( e.span(), - "The first line of the fsm definition should be `MachineName, CommandType, ErrorType`", + "The fsm definition should begin with `name MachineName; command CommandType; error ErrorType;` optionally followed by `shared_state SharedStateType;`", )); e })?; @@ -170,6 +190,7 @@ impl Parse for StateMachineDefinition { let transitions = transitions.into_iter().collect(); Ok(Self { name, + shared_state_type, transitions, command_type, error_type, @@ -177,13 +198,28 @@ impl Parse for StateMachineDefinition { } } -fn parse_first_line(input: &ParseStream) -> Result<(Ident, Ident, Ident)> { +fn parse_machine_types(input: &ParseStream) -> Result<(Ident, Ident, Ident, Option)> { + let _: kw::name = input.parse()?; let name: Ident = input.parse()?; - input.parse::()?; + input.parse::()?; + + let _: kw::command = input.parse()?; let command_type: Ident = input.parse()?; - input.parse::()?; + input.parse::()?; + + let _: kw::error = input.parse()?; let error_type: Ident = input.parse()?; - Ok((name, command_type, error_type)) + input.parse::()?; + + let shared_state_type: Option = if input.peek(kw::shared_state) { + let _: kw::shared_state = input.parse()?; + let typep = input.parse()?; + input.parse::()?; + Some(typep) + } else { + None + }; + Ok((name, command_type, error_type, shared_state_type)) } #[derive(Debug, Clone, Eq, PartialEq, Hash)] @@ -272,9 +308,22 @@ impl StateMachineDefinition { } }); let name = &self.name; - let main_enum = quote! { - #[derive(::derive_more::From)] - pub enum #name { + let state_enum_name = Ident::new(&format!("{}State", name), name.span()); + // If user has not defined any shared state, use the unit type. + let shared_state_type = self + .shared_state_type + .clone() + .unwrap_or_else(|| syn::parse_str("()").unwrap()); + let machine_struct = quote! { + #[derive(Clone)] + pub struct #name { + state: #state_enum_name, + shared_state: #shared_state_type + } + }; + let states_enum = quote! { + #[derive(::derive_more::From, Clone)] + pub enum #state_enum_name { #(#state_variants),* } }; @@ -354,37 +403,53 @@ impl StateMachineDefinition { quote! { _ => { return TransitionResult::InvalidTransition } }, )); quote! { - #name::#from(state_data) => match event { + #state_enum_name::#from(state_data) => match event { #(#event_branches),* } } }); let trait_impl = quote! { - impl ::rustfsm::StateMachine<#name, #events_enum_name, #cmd_type> for #name { + impl ::rustfsm::StateMachine for #name { type Error = #err_type; + type State = #state_enum_name; + type SharedState = #shared_state_type; + type Event = #events_enum_name; + type Command = #cmd_type; fn on_event(self, event: #events_enum_name) - -> ::rustfsm::TransitionResult<#name, Self::Error, #cmd_type> { - match self { + -> ::rustfsm::TransitionResult { + match self.state { #(#state_branches),* } } - fn state(&self) -> &Self { - &self + fn state(&self) -> &Self::State { + &self.state + } + fn set_state(&mut self, new: Self::State) { + self.state = new + } + + fn shared_state(&self) -> &Self::SharedState{ + &self.shared_state + } + + fn from_parts(shared: Self::SharedState, state: Self::State) -> Self { + Self { shared_state: shared, state } } } }; let transition_result_name = Ident::new(&format!("{}Transition", name), name.span()); let transition_type_alias = quote! { - type #transition_result_name = TransitionResult<#name, #err_type, #cmd_type>; + type #transition_result_name = TransitionResult<#name>; }; let output = quote! { #transition_type_alias - #main_enum + #machine_struct + #states_enum #events_enum #trait_impl }; diff --git a/fsm/state_machine_procmacro/tests/progress.rs b/fsm/state_machine_procmacro/tests/progress.rs index 36a59c500..5a3e4a4fc 100644 --- a/fsm/state_machine_procmacro/tests/progress.rs +++ b/fsm/state_machine_procmacro/tests/progress.rs @@ -10,9 +10,9 @@ fn tests() { t.compile_fail("tests/trybuild/*_fail.rs"); } -//Kept here to inspect manual expansion +// Kept here to inspect manual expansion state_machine_procmacro::fsm! { - SimpleMachine, SimpleMachineCommand, Infallible + name SimpleMachine; command SimpleMachineCommand; error Infallible; One --(A(String), foo)--> Two; One --(B)--> Two; @@ -20,7 +20,7 @@ state_machine_procmacro::fsm! { Two --(C, baz)--> One } -#[derive(Default)] +#[derive(Default, Clone)] pub struct One {} impl One { fn foo(self, _: String) -> SimpleMachineTransition { @@ -33,7 +33,7 @@ impl From for One { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Two {} impl Two { fn baz(self) -> SimpleMachineTransition { @@ -46,4 +46,4 @@ impl From for Two { } } -enum SimpleMachineCommand {} +pub enum SimpleMachineCommand {} diff --git a/fsm/state_machine_procmacro/tests/trybuild/forgot_name_fail.rs b/fsm/state_machine_procmacro/tests/trybuild/forgot_name_fail.rs index 4c21a01b4..f567a4148 100644 --- a/fsm/state_machine_procmacro/tests/trybuild/forgot_name_fail.rs +++ b/fsm/state_machine_procmacro/tests/trybuild/forgot_name_fail.rs @@ -6,7 +6,9 @@ fsm! { One --(A)--> Two } +#[derive(Default, Clone)] pub struct One {} +#[derive(Default, Clone)] pub struct Two {} fn main() {} diff --git a/fsm/state_machine_procmacro/tests/trybuild/forgot_name_fail.stderr b/fsm/state_machine_procmacro/tests/trybuild/forgot_name_fail.stderr index c7d3f6fff..9453ac13e 100644 --- a/fsm/state_machine_procmacro/tests/trybuild/forgot_name_fail.stderr +++ b/fsm/state_machine_procmacro/tests/trybuild/forgot_name_fail.stderr @@ -1,11 +1,11 @@ -error: expected `,` - --> $DIR/forgot_name_fail.rs:6:9 +error: expected `name` + --> $DIR/forgot_name_fail.rs:6:5 | 6 | One --(A)--> Two - | ^ + | ^^^ -error: The first line of the fsm definition should be `MachineName, CommandType, ErrorType` - --> $DIR/forgot_name_fail.rs:6:9 +error: The fsm definition should begin with `name MachineName; command CommandType; error ErrorType;` optionally followed by `shared_state SharedStateType;` + --> $DIR/forgot_name_fail.rs:6:5 | 6 | One --(A)--> Two - | ^ + | ^^^ diff --git a/fsm/state_machine_procmacro/tests/trybuild/handler_arg_pass.rs b/fsm/state_machine_procmacro/tests/trybuild/handler_arg_pass.rs index 1a792e705..1cd2b9ed8 100644 --- a/fsm/state_machine_procmacro/tests/trybuild/handler_arg_pass.rs +++ b/fsm/state_machine_procmacro/tests/trybuild/handler_arg_pass.rs @@ -5,23 +5,26 @@ use state_machine_trait::TransitionResult; use std::convert::Infallible; fsm! { - Simple, SimpleCommand, Infallible + name Simple; command SimpleCommand; error Infallible; One --(A(String), on_a)--> Two } +#[derive(Default, Clone)] pub struct One {} impl One { fn on_a(self, _: String) -> SimpleTransition { SimpleTransition::ok(vec![], Two {}) } } + +#[derive(Default, Clone)] pub struct Two {} pub enum SimpleCommand {} fn main() { - // main enum exists with both states - let _ = Simple::One(One {}); - let _ = Simple::Two(Two {}); + // state enum exists with both states + let _ = SimpleState::One(One {}); + let _ = SimpleState::Two(Two {}); } diff --git a/fsm/state_machine_procmacro/tests/trybuild/handler_pass.rs b/fsm/state_machine_procmacro/tests/trybuild/handler_pass.rs index 30fc7e056..196aa554b 100644 --- a/fsm/state_machine_procmacro/tests/trybuild/handler_pass.rs +++ b/fsm/state_machine_procmacro/tests/trybuild/handler_pass.rs @@ -5,23 +5,26 @@ use state_machine_trait::TransitionResult; use std::convert::Infallible; fsm! { - Simple, SimpleCommand, Infallible + name Simple; command SimpleCommand; error Infallible; One --(A, on_a)--> Two } +#[derive(Default, Clone)] pub struct One {} impl One { fn on_a(self) -> SimpleTransition { SimpleTransition::ok(vec![], Two {}) } } + +#[derive(Default, Clone)] pub struct Two {} pub enum SimpleCommand {} fn main() { - // main enum exists with both states - let _ = Simple::One(One {}); - let _ = Simple::Two(Two {}); + // state enum exists with both states + let _ = SimpleState::One(One {}); + let _ = SimpleState::Two(Two {}); } diff --git a/fsm/state_machine_procmacro/tests/trybuild/medium_complex_pass.rs b/fsm/state_machine_procmacro/tests/trybuild/medium_complex_pass.rs index 6479bc159..1a2cda97c 100644 --- a/fsm/state_machine_procmacro/tests/trybuild/medium_complex_pass.rs +++ b/fsm/state_machine_procmacro/tests/trybuild/medium_complex_pass.rs @@ -5,7 +5,7 @@ use state_machine_trait::TransitionResult; use std::convert::Infallible; fsm! { - SimpleMachine, SimpleMachineCommand, Infallible + name SimpleMachine; command SimpleMachineCommand; error Infallible; One --(A(String), foo)--> Two; One --(B)--> Two; @@ -13,7 +13,7 @@ fsm! { Two --(C, baz)--> One } -#[derive(Default)] +#[derive(Default, Clone)] pub struct One {} impl One { fn foo(self, _: String) -> SimpleMachineTransition { @@ -26,7 +26,7 @@ impl From for One { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Two {} impl Two { fn baz(self) -> SimpleMachineTransition { @@ -39,6 +39,6 @@ impl From for Two { } } -enum SimpleMachineCommand {} +pub enum SimpleMachineCommand {} fn main() {} diff --git a/fsm/state_machine_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.rs b/fsm/state_machine_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.rs index 8d5080563..3b187131e 100644 --- a/fsm/state_machine_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.rs +++ b/fsm/state_machine_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.rs @@ -5,14 +5,16 @@ use state_machine_trait::TransitionResult; use std::convert::Infallible; fsm! { - SimpleMachine, SimpleMachineCommand, Infallible + name SimpleMachine; command SimpleMachineCommand; error Infallible; One --(A)--> Two; Two --(B)--> One; } +#[derive(Default, Clone)] pub struct One {} +#[derive(Default, Clone)] pub struct Two {} // We implement one of them because trait bound satisfaction error output is not deterministically // ordered diff --git a/fsm/state_machine_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr b/fsm/state_machine_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr index ddb471296..487e5f969 100644 --- a/fsm/state_machine_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr +++ b/fsm/state_machine_procmacro/tests/trybuild/no_handle_conversions_require_into_fail.stderr @@ -5,4 +5,4 @@ error[E0277]: the trait bound `One: From` is not satisfied | ^^^ the trait `From` is not implemented for `One` | = note: required because of the requirements on the impl of `Into` for `Two` - = note: required by `TransitionResult::::from` + = note: required by `TransitionResult::::from` diff --git a/fsm/state_machine_procmacro/tests/trybuild/simple_pass.rs b/fsm/state_machine_procmacro/tests/trybuild/simple_pass.rs index 46fe99ae7..545659588 100644 --- a/fsm/state_machine_procmacro/tests/trybuild/simple_pass.rs +++ b/fsm/state_machine_procmacro/tests/trybuild/simple_pass.rs @@ -5,13 +5,15 @@ use state_machine_trait::TransitionResult; use std::convert::Infallible; fsm! { - SimpleMachine, SimpleMachineCommand, Infallible + name SimpleMachine; command SimpleMachineCommand; error Infallible; One --(A)--> Two } +#[derive(Default, Clone)] pub struct One {} +#[derive(Default, Clone)] pub struct Two {} impl From for Two { fn from(_: One) -> Self { @@ -22,9 +24,9 @@ impl From for Two { pub enum SimpleMachineCommand {} fn main() { - // main enum exists with both states - let _ = SimpleMachine::One(One {}); - let _ = SimpleMachine::Two(Two {}); + // state enum exists with both states + let _ = SimpleMachineState::One(One {}); + let _ = SimpleMachineState::Two(Two {}); // Event enum exists let _ = SimpleMachineEvents::A; } diff --git a/fsm/state_machine_procmacro/tests/trybuild/struct_event_variant_fail.rs b/fsm/state_machine_procmacro/tests/trybuild/struct_event_variant_fail.rs index d2d9bca50..6447b8269 100644 --- a/fsm/state_machine_procmacro/tests/trybuild/struct_event_variant_fail.rs +++ b/fsm/state_machine_procmacro/tests/trybuild/struct_event_variant_fail.rs @@ -3,12 +3,14 @@ extern crate state_machine_trait as rustfsm; use state_machine_procmacro::fsm; fsm! { - Simple, SimpleCommand, Infallible + name Simple; command SimpleCommand; error Infallible; One --(A{foo: String}, on_a)--> Two } +#[derive(Default, Clone)] pub struct One {} +#[derive(Default, Clone)] pub struct Two {} pub enum SimpleCommand {} diff --git a/fsm/state_machine_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.rs b/fsm/state_machine_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.rs index f15eb6db7..80235de24 100644 --- a/fsm/state_machine_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.rs +++ b/fsm/state_machine_procmacro/tests/trybuild/tuple_more_item_event_variant_fail.rs @@ -3,7 +3,7 @@ extern crate state_machine_trait as rustfsm; use state_machine_procmacro::fsm; fsm! { - Simple, SimpleCmd, Infallible + name Simple; command SimpleCmd; error Infallible; One --(A(Foo, Bar), on_a)--> Two } diff --git a/fsm/state_machine_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.rs b/fsm/state_machine_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.rs index fd1d885b7..598f853c0 100644 --- a/fsm/state_machine_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.rs +++ b/fsm/state_machine_procmacro/tests/trybuild/tuple_zero_item_event_variant_fail.rs @@ -3,7 +3,7 @@ extern crate state_machine_trait as rustfsm; use state_machine_procmacro::fsm; fsm! { - Simple, SimpleCmd, Infallible + name Simple; command SimpleCmd; error Infallible; One --(A(), on_a)--> Two } diff --git a/fsm/state_machine_trait/src/lib.rs b/fsm/state_machine_trait/src/lib.rs index 6efe99644..a205ce3d1 100644 --- a/fsm/state_machine_trait/src/lib.rs +++ b/fsm/state_machine_trait/src/lib.rs @@ -1,47 +1,162 @@ use std::error::Error; +use std::fmt::{Debug, Display, Formatter}; /// This trait defines a state machine (more formally, a [finite state /// transducer](https://en.wikipedia.org/wiki/Finite-state_transducer)) which accepts events (the /// input alphabet), uses them to mutate itself, and (may) output some commands (the output /// alphabet) as a result. -/// -/// The `State`, `Event`, and `Command` type parameters will generally be enumerations -pub trait StateMachine { +pub trait StateMachine: Sized { /// The error type produced by this state machine when handling events type Error: Error; + /// The type used to represent different machine states. Should be an enum. + type State; + /// The type used to represent state that common among all states. Should be a struct. + type SharedState; + /// The type used to represent events the machine handles. Should be an enum. + type Event; + /// The type used to represent commands the machine issues upon transitions. + type Command; - /// Handle an incoming event - fn on_event(self, event: Event) -> TransitionResult; + /// Handle an incoming event, returning a transition result which represents updates to apply + /// to the state machine. + fn on_event(self, event: Self::Event) -> TransitionResult; - /// Returns the current state of the machine - fn state(&self) -> &State; + /// Handle an incoming event and mutate the state machine to update to the new state and apply + /// any changes to shared state. + /// + /// Returns the commands issued by the transition on success, otherwise a [MachineError] + fn on_event_mut( + &mut self, + event: Self::Event, + ) -> Result, MachineError> + where + Self: Clone, + { + // NOTE: This clone is actually nice in some sense, giving us a kind of transactionality. + // However if there are really big things in state it could be an issue. + let res = self.clone().on_event(event); + match res { + TransitionResult::Ok { + commands, + new_state, + shared_state, + } => { + *self = Self::from_parts(shared_state, new_state); + Ok(commands) + } + TransitionResult::OkNoShare { + commands, + new_state, + } => { + self.set_state(new_state); + Ok(commands) + } + TransitionResult::InvalidTransition => Err(MachineError::InvalidTransition), + TransitionResult::Err(e) => Err(MachineError::Underlying(e)), + } + } + + fn state(&self) -> &Self::State; + fn set_state(&mut self, new_state: Self::State); + + fn shared_state(&self) -> &Self::SharedState; + + /// Given the shared data and new state, create a new instance. + fn from_parts(shared: Self::SharedState, state: Self::State) -> Self; +} + +/// The error returned by [StateMachine]s when handling events +#[derive(Debug)] +pub enum MachineError { + /// An undefined transition was attempted + InvalidTransition, + /// Some error occurred while processing the transition + Underlying(E), +} + +impl Display for MachineError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + MachineError::InvalidTransition => f.write_str("Invalid transition"), + MachineError::Underlying(e) => Display::fmt(&e, f), + } + } +} +impl Error for MachineError {} + +pub enum MachineUpdate +where + Machine: StateMachine, +{ + InvalidTransition, + Ok { commands: Vec }, +} + +impl MachineUpdate +where + M: StateMachine, +{ + /// Unwraps the machine update, panicking if the transition was invalid. + pub fn unwrap(self) -> Vec { + match self { + Self::Ok { commands } => commands, + _ => panic!("Transition was not successful!"), + } + } } -// TODO: Likely need to return existing state with invalid trans/err /// A transition result is emitted every time the [StateMachine] handles an event. -pub enum TransitionResult { +pub enum TransitionResult +where + Machine: StateMachine, +{ /// This state does not define a transition for this event from this state. All other errors /// should use the [Err](enum.TransitionResult.html#variant.Err) variant. InvalidTransition, /// The transition was successful Ok { - commands: Vec, - new_state: StateMachine, + commands: Vec, + new_state: Machine::State, + shared_state: Machine::SharedState, + }, + /// The transition was successful with no shared state change + OkNoShare { + commands: Vec, + new_state: Machine::State, }, /// There was some error performing the transition - Err(StateMachineError), + Err(Machine::Error), } -impl TransitionResult { - /// Produce a transition with the provided commands to the provided state +impl TransitionResult +where + S: StateMachine, +{ + /// Produce a transition with the provided commands to the provided state. No changes to shared + /// state if it exists pub fn ok(commands: CI, new_state: IS) -> Self where - CI: IntoIterator, - IS: Into, + CI: IntoIterator, + IS: Into, + { + Self::OkNoShare { + commands: commands.into_iter().collect(), + new_state: new_state.into(), + } + } + + /// Produce a transition with the provided commands to the provided state with shared state + /// changes + pub fn ok_shared(commands: CI, new_state: IS, new_shared: SS) -> Self + where + CI: IntoIterator, + IS: Into, + SS: Into, { Self::Ok { commands: commands.into_iter().collect(), new_state: new_state.into(), + shared_state: new_shared.into(), } } @@ -49,9 +164,9 @@ impl TransitionResult { /// value pub fn default() -> Self where - DestState: Into + Default, + DestState: Into + Default, { - Self::Ok { + Self::OkNoShare { commands: vec![], new_state: DestState::default().into(), } @@ -61,24 +176,13 @@ impl TransitionResult { /// the provided (by type parameter) destination state. pub fn from(current_state: CurrentState) -> Self where - DestState: Into, + DestState: Into, CurrentState: Into, { let as_dest: DestState = current_state.into(); - Self::Ok { + Self::OkNoShare { commands: vec![], new_state: as_dest.into(), } } - - // TODO: Make test only or something? - pub fn unwrap(self) -> (S, Vec) { - match self { - Self::Ok { - commands, - new_state, - } => (new_state, commands), - _ => panic!("Transition was not successful!"), - } - } } diff --git a/fsm/tests/card_reader.rs b/fsm/tests/card_reader.rs deleted file mode 100644 index 23fd44e78..000000000 --- a/fsm/tests/card_reader.rs +++ /dev/null @@ -1,139 +0,0 @@ -//! We'll imagine a (idealized) card reader which unlocks a door / blinks a light when it's open -//! -//! This is the by-hand version, useful to compare to the macro version in the docs - -use state_machine_trait::{StateMachine, TransitionResult}; - -#[derive(Clone)] -pub enum CardReader { - Locked(Locked), - ReadingCard(ReadingCard), - Unlocked(DoorOpen), -} - -#[derive(thiserror::Error, Debug)] -pub enum CardReaderError {} - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub enum CardReaderEvents { - /// Someone's presented a card for reading - CardReadable(CardData), - /// Door latch connected - DoorClosed, - CardAccepted, - CardRejected, -} - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub enum Commands { - StartBlinkingLight, - StopBlinkingLight, - ProcessData(CardData), -} - -type CardData = String; - -impl CardReader { - /// Reader starts locked - pub fn new() -> Self { - CardReader::Locked(Locked {}) - } -} - -impl StateMachine for CardReader { - type Error = CardReaderError; - - fn on_event(self, event: CardReaderEvents) -> TransitionResult { - let mut commands = vec![]; - let new_state = match self { - CardReader::Locked(ls) => match event { - CardReaderEvents::CardReadable(data) => { - commands.push(Commands::ProcessData(data.clone())); - commands.push(Commands::StartBlinkingLight); - Self::ReadingCard(ls.on_card_readable(data)) - } - _ => return TransitionResult::InvalidTransition, - }, - CardReader::ReadingCard(rc) => match event { - CardReaderEvents::CardAccepted => { - commands.push(Commands::StopBlinkingLight); - Self::Unlocked(rc.on_card_accepted()) - } - CardReaderEvents::CardRejected => { - commands.push(Commands::StopBlinkingLight); - Self::Locked(rc.on_card_rejected()) - } - _ => return TransitionResult::InvalidTransition, - }, - CardReader::Unlocked(_) => match event { - CardReaderEvents::DoorClosed => Self::Locked(Locked {}), - _ => return TransitionResult::InvalidTransition, - }, - }; - TransitionResult::Ok { - commands, - new_state, - } - } - - fn state(&self) -> &CardReader { - self - } -} - -/// Door is locked / idle / we are ready to read -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct Locked {} - -/// Actively reading the card -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct ReadingCard { - card_data: CardData, -} - -/// The door is open, we shouldn't be accepting cards and should be blinking the light -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct DoorOpen {} - -impl Locked { - fn on_card_readable(&self, data: CardData) -> ReadingCard { - ReadingCard { card_data: data } - } -} - -impl ReadingCard { - fn on_card_accepted(&self) -> DoorOpen { - DoorOpen {} - } - fn on_card_rejected(&self) -> Locked { - Locked {} - } -} - -#[cfg(test)] -mod tests { - use super::*; - - // Should be kept the same the main example doctest - #[test] - fn run_a_card_reader() { - let cr = CardReader::Locked(Locked {}); - let (cr, cmds) = cr - .on_event(CardReaderEvents::CardReadable("badguy".to_string())) - .unwrap(); - assert_eq!(cmds[0], Commands::ProcessData("badguy".to_string())); - assert_eq!(cmds[1], Commands::StartBlinkingLight); - - let (cr, cmds) = cr.on_event(CardReaderEvents::CardRejected).unwrap(); - assert_eq!(cmds[0], Commands::StopBlinkingLight); - - let (cr, cmds) = cr - .on_event(CardReaderEvents::CardReadable("goodguy".to_string())) - .unwrap(); - assert_eq!(cmds[0], Commands::ProcessData("goodguy".to_string())); - assert_eq!(cmds[1], Commands::StartBlinkingLight); - - let (_, cmds) = cr.on_event(CardReaderEvents::CardAccepted).unwrap(); - assert_eq!(cmds[0], Commands::StopBlinkingLight); - } -} diff --git a/src/machines/activity_state_machine.rs b/src/machines/activity_state_machine.rs index c9a9398e2..66ac7aabd 100644 --- a/src/machines/activity_state_machine.rs +++ b/src/machines/activity_state_machine.rs @@ -3,7 +3,7 @@ use rustfsm::{fsm, TransitionResult}; // Schedule / cancel are "explicit events" (imperative rather than past events?) fsm! { - ActivityMachine, ActivityCommand, ActivityMachineError + name ActivityMachine; command ActivityCommand; error ActivityMachineError; Created --(Schedule, on_schedule)--> ScheduleCommandCreated; @@ -54,7 +54,7 @@ pub enum ActivityMachineError {} pub enum ActivityCommand {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { @@ -64,7 +64,7 @@ impl Created { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct ScheduleCommandCreated {} impl ScheduleCommandCreated { @@ -79,7 +79,7 @@ impl ScheduleCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct ScheduledEventRecorded {} impl ScheduledEventRecorded { @@ -97,7 +97,7 @@ impl ScheduledEventRecorded { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Started {} impl Started { @@ -119,7 +119,7 @@ impl Started { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct ScheduledActivityCancelCommandCreated {} impl ScheduledActivityCancelCommandCreated { @@ -129,7 +129,7 @@ impl ScheduledActivityCancelCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct ScheduledActivityCancelEventRecorded {} impl ScheduledActivityCancelEventRecorded { @@ -149,7 +149,7 @@ impl From for ScheduledActivityCancelEven } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct StartedActivityCancelCommandCreated {} impl StartedActivityCancelCommandCreated { @@ -159,7 +159,7 @@ impl StartedActivityCancelCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct StartedActivityCancelEventRecorded {} impl StartedActivityCancelEventRecorded { @@ -187,16 +187,16 @@ impl From for StartedActivityCancelEventRe } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Completed {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Failed {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct TimedOut {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Canceled {} #[cfg(test)] diff --git a/src/machines/cancel_external_state_machine.rs b/src/machines/cancel_external_state_machine.rs index c85e4fa58..45cfc48f6 100644 --- a/src/machines/cancel_external_state_machine.rs +++ b/src/machines/cancel_external_state_machine.rs @@ -1,7 +1,7 @@ use rustfsm::{fsm, TransitionResult}; fsm! { - CancelExternalMachine, CancelExternalCommand, CancelExternalMachineError + name CancelExternalMachine; command CancelExternalCommand; error CancelExternalMachineError; Created --(Schedule, on_schedule) --> RequestCancelExternalCommandCreated; @@ -17,10 +17,10 @@ pub enum CancelExternalMachineError {} pub enum CancelExternalCommand {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct CancelRequested {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { @@ -29,7 +29,7 @@ impl Created { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct RequestCancelExternalCommandCreated {} impl RequestCancelExternalCommandCreated { @@ -40,7 +40,7 @@ impl RequestCancelExternalCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct RequestCancelExternalCommandRecorded {} impl RequestCancelExternalCommandRecorded { @@ -56,5 +56,5 @@ impl RequestCancelExternalCommandRecorded { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct RequestCancelFailed {} diff --git a/src/machines/cancel_workflow_state_machine.rs b/src/machines/cancel_workflow_state_machine.rs index 150a56bda..e60175615 100644 --- a/src/machines/cancel_workflow_state_machine.rs +++ b/src/machines/cancel_workflow_state_machine.rs @@ -1,7 +1,7 @@ use rustfsm::{fsm, TransitionResult}; fsm! { - CancelWorkflowMachine, CancelWorkflowCommand, CancelWorkflowMachineError + name CancelWorkflowMachine; command CancelWorkflowCommand; error CancelWorkflowMachineError; CancelWorkflowCommandCreated --(CommandCancelWorkflowExecution) --> CancelWorkflowCommandCreated; CancelWorkflowCommandCreated --(WorkflowExecutionCanceled, on_workflow_execution_canceled) --> CancelWorkflowCommandRecorded; @@ -14,7 +14,7 @@ pub enum CancelWorkflowMachineError {} pub enum CancelWorkflowCommand {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct CancelWorkflowCommandCreated {} impl CancelWorkflowCommandCreated { @@ -23,10 +23,10 @@ impl CancelWorkflowCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct CancelWorkflowCommandRecorded {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { diff --git a/src/machines/child_workflow_state_machine.rs b/src/machines/child_workflow_state_machine.rs index 91d219323..fc5e30ad6 100644 --- a/src/machines/child_workflow_state_machine.rs +++ b/src/machines/child_workflow_state_machine.rs @@ -1,7 +1,7 @@ use rustfsm::{fsm, TransitionResult}; fsm! { - ChildWorkflowMachine, ChildWorkflowCommand, ChildWorkflowMachineError + name ChildWorkflowMachine; command ChildWorkflowCommand; error ChildWorkflowMachineError; Created --(Schedule, on_schedule) --> StartCommandCreated; @@ -24,13 +24,13 @@ pub enum ChildWorkflowMachineError {} pub enum ChildWorkflowCommand {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Canceled {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Completed {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { @@ -39,10 +39,10 @@ impl Created { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Failed {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct StartCommandCreated {} impl StartCommandCreated { @@ -54,7 +54,7 @@ impl StartCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct StartEventRecorded {} impl StartEventRecorded { @@ -66,10 +66,10 @@ impl StartEventRecorded { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct StartFailed {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Started {} impl Started { @@ -90,8 +90,8 @@ impl Started { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Terminated {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct TimedOut {} diff --git a/src/machines/complete_workflow_state_machine.rs b/src/machines/complete_workflow_state_machine.rs index d16ae8b00..d1cbe455a 100644 --- a/src/machines/complete_workflow_state_machine.rs +++ b/src/machines/complete_workflow_state_machine.rs @@ -1,7 +1,7 @@ use rustfsm::{fsm, TransitionResult}; fsm! { - CompleteWorkflowMachine, CompleteWorkflowCommand, CompleteWorkflowMachineError + name CompleteWorkflowMachine; command CompleteWorkflowCommand; error CompleteWorkflowMachineError; CompleteWorkflowCommandCreated --(CommandCompleteWorkflowExecution) --> CompleteWorkflowCommandCreated; CompleteWorkflowCommandCreated --(WorkflowExecutionCompleted, on_workflow_execution_completed) --> CompleteWorkflowCommandRecorded; @@ -14,7 +14,7 @@ pub enum CompleteWorkflowMachineError {} pub enum CompleteWorkflowCommand {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct CompleteWorkflowCommandCreated {} impl CompleteWorkflowCommandCreated { @@ -23,10 +23,10 @@ impl CompleteWorkflowCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct CompleteWorkflowCommandRecorded {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { diff --git a/src/machines/continue_as_new_workflow_state_machine.rs b/src/machines/continue_as_new_workflow_state_machine.rs index 66a787b68..4a45d15b2 100644 --- a/src/machines/continue_as_new_workflow_state_machine.rs +++ b/src/machines/continue_as_new_workflow_state_machine.rs @@ -1,7 +1,7 @@ use rustfsm::{fsm, TransitionResult}; fsm! { - ContinueAsNewWorkflowMachine, ContinueAsNewWorkflowCommand, ContinueAsNewWorkflowMachineError + name ContinueAsNewWorkflowMachine; command ContinueAsNewWorkflowCommand; error ContinueAsNewWorkflowMachineError; ContinueAsNewWorkflowCommandCreated --(CommandContinueAsNewWorkflowExecution) --> ContinueAsNewWorkflowCommandCreated; ContinueAsNewWorkflowCommandCreated --(WorkflowExecutionContinuedAsNew, on_workflow_execution_continued_as_new) --> ContinueAsNewWorkflowCommandRecorded; @@ -14,7 +14,7 @@ pub enum ContinueAsNewWorkflowMachineError {} pub enum ContinueAsNewWorkflowCommand {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct ContinueAsNewWorkflowCommandCreated {} impl ContinueAsNewWorkflowCommandCreated { @@ -23,10 +23,10 @@ impl ContinueAsNewWorkflowCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct ContinueAsNewWorkflowCommandRecorded {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { diff --git a/src/machines/fail_workflow_state_machine.rs b/src/machines/fail_workflow_state_machine.rs index 341ca2316..872d9cacd 100644 --- a/src/machines/fail_workflow_state_machine.rs +++ b/src/machines/fail_workflow_state_machine.rs @@ -1,7 +1,7 @@ use rustfsm::{fsm, TransitionResult}; fsm! { - FailWorkflowMachine, FailWorkflowCommand, FailWorkflowMachineError + name FailWorkflowMachine; command FailWorkflowCommand; error FailWorkflowMachineError; Created --(Schedule, on_schedule) --> FailWorkflowCommandCreated; @@ -14,7 +14,7 @@ pub enum FailWorkflowMachineError {} pub enum FailWorkflowCommand {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { @@ -23,7 +23,7 @@ impl Created { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct FailWorkflowCommandCreated {} impl FailWorkflowCommandCreated { @@ -32,5 +32,5 @@ impl FailWorkflowCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct FailWorkflowCommandRecorded {} diff --git a/src/machines/local_activity_state_machine.rs b/src/machines/local_activity_state_machine.rs index 446ef099b..d275ab49f 100644 --- a/src/machines/local_activity_state_machine.rs +++ b/src/machines/local_activity_state_machine.rs @@ -1,7 +1,7 @@ use rustfsm::{fsm, TransitionResult}; fsm! { - LocalActivityMachine, LocalActivityCommand, LocalActivityMachineError + name LocalActivityMachine; command LocalActivityCommand; error LocalActivityMachineError; Created --(CheckExecutionState, on_check_execution_state) --> Replaying; Created --(CheckExecutionState, on_check_execution_state) --> Executing; @@ -28,7 +28,7 @@ pub enum LocalActivityMachineError {} pub enum LocalActivityCommand {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { @@ -37,7 +37,7 @@ impl Created { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Executing {} impl Executing { @@ -46,7 +46,7 @@ impl Executing { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct MarkerCommandCreated {} impl MarkerCommandCreated { @@ -55,16 +55,16 @@ impl MarkerCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct MarkerCommandRecorded {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Replaying {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct RequestPrepared {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct RequestSent {} impl RequestSent { @@ -79,7 +79,7 @@ impl From for RequestSent { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct ResultNotified {} impl ResultNotified { @@ -88,7 +88,7 @@ impl ResultNotified { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct WaitingMarkerEvent {} impl WaitingMarkerEvent { diff --git a/src/machines/mutable_side_effect_state_machine.rs b/src/machines/mutable_side_effect_state_machine.rs index ede0f1f05..c75d88f06 100644 --- a/src/machines/mutable_side_effect_state_machine.rs +++ b/src/machines/mutable_side_effect_state_machine.rs @@ -1,7 +1,7 @@ use rustfsm::{fsm, TransitionResult}; fsm! { - MutableSideEffectMachine, MutableSideEffectCommand, MutableSideEffectMachineError + name MutableSideEffectMachine; command MutableSideEffectCommand; error MutableSideEffectMachineError; Created --(CheckExecutionState, on_check_execution_state) --> Replaying; Created --(CheckExecutionState, on_check_execution_state) --> Executing; @@ -29,7 +29,7 @@ pub enum MutableSideEffectMachineError {} pub enum MutableSideEffectCommand {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { @@ -38,7 +38,7 @@ impl Created { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Executing {} impl Executing { @@ -47,7 +47,7 @@ impl Executing { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct MarkerCommandCreated {} impl MarkerCommandCreated { @@ -56,13 +56,13 @@ impl MarkerCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct MarkerCommandCreatedReplaying {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct MarkerCommandRecorded {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Replaying {} impl Replaying { @@ -71,7 +71,7 @@ impl Replaying { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct ResultNotified {} impl ResultNotified { @@ -80,7 +80,7 @@ impl ResultNotified { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct ResultNotifiedReplaying {} impl ResultNotifiedReplaying { @@ -98,7 +98,7 @@ impl From for ResultNotifiedReplaying { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Skipped {} impl Skipped { @@ -107,5 +107,5 @@ impl Skipped { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct SkippedNotified {} diff --git a/src/machines/side_effect_state_machine.rs b/src/machines/side_effect_state_machine.rs index 26d7ef21b..29aed6606 100644 --- a/src/machines/side_effect_state_machine.rs +++ b/src/machines/side_effect_state_machine.rs @@ -1,7 +1,7 @@ use rustfsm::{fsm, TransitionResult}; fsm! { - SideEffectMachine, SideEffectCommand, SideEffectMachineError + name SideEffectMachine; command SideEffectCommand; error SideEffectMachineError; Created --(Schedule, on_schedule) --> MarkerCommandCreated; Created --(Schedule, on_schedule) --> MarkerCommandCreatedReplaying; @@ -20,7 +20,7 @@ pub enum SideEffectMachineError {} pub enum SideEffectCommand {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { @@ -29,7 +29,7 @@ impl Created { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct MarkerCommandCreated {} impl MarkerCommandCreated { @@ -38,13 +38,13 @@ impl MarkerCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct MarkerCommandCreatedReplaying {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct MarkerCommandRecorded {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct ResultNotified {} impl ResultNotified { @@ -53,7 +53,7 @@ impl ResultNotified { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct ResultNotifiedReplaying {} impl ResultNotifiedReplaying { diff --git a/src/machines/signal_external_state_machine.rs b/src/machines/signal_external_state_machine.rs index 9a9d720cd..a50b57a01 100644 --- a/src/machines/signal_external_state_machine.rs +++ b/src/machines/signal_external_state_machine.rs @@ -1,7 +1,7 @@ use rustfsm::{fsm, TransitionResult}; fsm! { - SignalExternalMachine, SignalExternalCommand, SignalExternalMachineError + name SignalExternalMachine; command SignalExternalCommand; error SignalExternalMachineError; Created --(Schedule, on_schedule) --> SignalExternalCommandCreated; @@ -19,10 +19,10 @@ pub enum SignalExternalMachineError {} pub enum SignalExternalCommand {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Canceled {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { @@ -31,10 +31,10 @@ impl Created { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Failed {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct SignalExternalCommandCreated {} impl SignalExternalCommandCreated { @@ -48,7 +48,7 @@ impl SignalExternalCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct SignalExternalCommandRecorded {} impl SignalExternalCommandRecorded { @@ -60,5 +60,5 @@ impl SignalExternalCommandRecorded { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Signaled {} diff --git a/src/machines/timer_state_machine.rs b/src/machines/timer_state_machine.rs index eb1eef9e9..e22f99b9d 100644 --- a/src/machines/timer_state_machine.rs +++ b/src/machines/timer_state_machine.rs @@ -1,7 +1,10 @@ use rustfsm::{fsm, TransitionResult}; fsm! { - TimerMachine, TimerCommand, TimerMachineError + name TimerMachine; + command TimerCommand; + error TimerMachineError; + shared_state SharedState; CancelTimerCommandCreated --(Cancel) --> CancelTimerCommandCreated; CancelTimerCommandCreated --(CommandCancelTimer, on_command_cancel_timer) --> CancelTimerCommandSent; @@ -18,64 +21,103 @@ fsm! { StartCommandRecorded --(Cancel, on_cancel) --> CancelTimerCommandCreated; } +#[derive(Default, Clone)] +pub struct SharedState {} + #[derive(thiserror::Error, Debug)] pub enum TimerMachineError {} -pub enum TimerCommand {} +pub enum TimerCommand { + StartTimer(/* TODO: Command attribs */), + CancelTimer(/* TODO: Command attribs */), +} -#[derive(Default)] +#[derive(Default, Clone)] pub struct CancelTimerCommandCreated {} - impl CancelTimerCommandCreated { pub fn on_command_cancel_timer(self) -> TimerMachineTransition { + // TODO: Need to call notify_cancellation - but have no ref to machine unimplemented!() } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct CancelTimerCommandSent {} - impl CancelTimerCommandSent { pub fn on_timer_canceled(self) -> TimerMachineTransition { unimplemented!() } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Canceled {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { pub fn on_schedule(self) -> TimerMachineTransition { - unimplemented!() + TimerMachineTransition::ok( + vec![TimerCommand::StartTimer()], + StartCommandCreated::default(), + ) } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Fired {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct StartCommandCreated {} impl StartCommandCreated { pub fn on_timer_started(self) -> TimerMachineTransition { + // Record initial event ID unimplemented!() } pub fn on_cancel(self) -> TimerMachineTransition { + // Cancel the initial command - which just sets a "canceled" flag in a wrapper of a + // proto command. unimplemented!() } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct StartCommandRecorded {} impl StartCommandRecorded { pub fn on_timer_fired(self) -> TimerMachineTransition { + // Complete callback with timer fired event unimplemented!() } pub fn on_cancel(self) -> TimerMachineTransition { + TimerMachineTransition::ok( + vec![TimerCommand::CancelTimer()], + CancelTimerCommandCreated::default(), + ) + } +} + +impl TimerMachine { + fn notify_cancellation(&self) { + // TODO: Needs access to shared state + // "notify cancellation" + /* + completionCallback.apply( + HistoryEvent.newBuilder() + .setEventType(EventType.EVENT_TYPE_TIMER_CANCELED) + .setTimerCanceledEventAttributes( + TimerCanceledEventAttributes.newBuilder() + .setIdentity("workflow") + .setTimerId(startAttributes.getTimerId())) + .build()); + */ unimplemented!() } } + +#[cfg(test)] +mod test { + #[test] + fn wat() {} +} diff --git a/src/machines/upsert_search_attributes_state_machine.rs b/src/machines/upsert_search_attributes_state_machine.rs index 1b07c80e7..874689b6d 100644 --- a/src/machines/upsert_search_attributes_state_machine.rs +++ b/src/machines/upsert_search_attributes_state_machine.rs @@ -1,7 +1,7 @@ use rustfsm::{fsm, TransitionResult}; fsm! { - UpsertSearchAttributesMachine, UpsertSearchAttributesCommand, UpsertSearchAttributesMachineError + name UpsertSearchAttributesMachine; command UpsertSearchAttributesCommand; error UpsertSearchAttributesMachineError; Created --(Schedule, on_schedule) --> UpsertCommandCreated; @@ -14,7 +14,7 @@ pub enum UpsertSearchAttributesMachineError {} pub enum UpsertSearchAttributesCommand {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { @@ -23,7 +23,7 @@ impl Created { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct UpsertCommandCreated {} impl UpsertCommandCreated { @@ -32,5 +32,5 @@ impl UpsertCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct UpsertCommandRecorded {} diff --git a/src/machines/version_state_machine.rs b/src/machines/version_state_machine.rs index b8c2fe254..fc6846dbd 100644 --- a/src/machines/version_state_machine.rs +++ b/src/machines/version_state_machine.rs @@ -1,7 +1,7 @@ use rustfsm::{fsm, TransitionResult}; fsm! { - VersionMachine, VersionCommand, VersionMachineError + name VersionMachine; command VersionCommand; error VersionMachineError; Created --(CheckExecutionState, on_check_execution_state) --> Replaying; Created --(CheckExecutionState, on_check_execution_state) --> Executing; @@ -29,7 +29,7 @@ pub enum VersionMachineError {} pub enum VersionCommand {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { @@ -38,7 +38,7 @@ impl Created { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Executing {} impl Executing { @@ -47,7 +47,7 @@ impl Executing { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct MarkerCommandCreated {} impl MarkerCommandCreated { @@ -56,13 +56,13 @@ impl MarkerCommandCreated { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct MarkerCommandCreatedReplaying {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct MarkerCommandRecorded {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Replaying {} impl Replaying { @@ -71,7 +71,7 @@ impl Replaying { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct ResultNotified {} impl ResultNotified { @@ -80,7 +80,7 @@ impl ResultNotified { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct ResultNotifiedReplaying {} impl ResultNotifiedReplaying { @@ -98,7 +98,7 @@ impl From for ResultNotifiedReplaying { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Skipped {} impl Skipped { @@ -107,5 +107,5 @@ impl Skipped { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct SkippedNotified {} diff --git a/src/machines/workflow_task_state_machine.rs b/src/machines/workflow_task_state_machine.rs index a22a5641a..15a0a8292 100644 --- a/src/machines/workflow_task_state_machine.rs +++ b/src/machines/workflow_task_state_machine.rs @@ -1,7 +1,7 @@ use rustfsm::{fsm, TransitionResult}; fsm! { - WorkflowTaskMachine, WorkflowTaskCommand, WorkflowTaskMachineError + name WorkflowTaskMachine; command WorkflowTaskCommand; error WorkflowTaskMachineError; Created --(WorkflowTaskScheduled, on_workflow_task_scheduled) --> Scheduled; @@ -18,10 +18,10 @@ pub enum WorkflowTaskMachineError {} pub enum WorkflowTaskCommand {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Completed {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Created {} impl Created { @@ -30,10 +30,10 @@ impl Created { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Failed {} -#[derive(Default)] +#[derive(Default, Clone)] pub struct Scheduled {} impl Scheduled { @@ -45,7 +45,7 @@ impl Scheduled { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct Started {} impl Started { @@ -60,5 +60,5 @@ impl Started { } } -#[derive(Default)] +#[derive(Default, Clone)] pub struct TimedOut {}