1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
use crate::suspended_event::SuspendedEvent; use crate::transition_event::TransitionEvent; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; /// This trait provides the methods that Aper needs to be able to interact with /// an object as a state machine. /// /// None of the methods in this trait provide access to the internal data of the /// state machine. It's up to you to implement accessor methods (or use public /// fields) in order to expose the data necessary to render your views. pub trait StateMachine: Sized + Unpin + 'static + Send + Clone + Serialize + for<'d> Deserialize<'d> { /// The [StateMachine::Transition] type associates another type with this state machine /// as its transitions. type Transition: Sized + Unpin + 'static + Send + PartialEq + Clone + Serialize + for<'d> Deserialize<'d>; /// Update the state machine according to the given [TransitionEvent]. This method *must* be /// deterministic: calling it on a clone of the state with a clone of the [TransitionEvent] /// must result in the same state, even at a different time and on a different machine. This /// is the requirement that allows Aper to keep the state in sync across multiple machines. fn process_event(&mut self, transition_event: TransitionEvent<Self::Transition>); /// A state machine may "suspend" an event which occurs at a specific time in the future. /// This is useful for ensuring that the state is updated at a future time regardless of /// a user-initiated state change before then. State machines that only change state as a /// result of user-initiated events can ignore this method, as the default implementation /// is to never suspend an event. /// /// This method is called by the server once after every call to `process_event`. If it /// returns `None`, no event is suspended, and any previously suspended event is cancelled. /// If it returns `Some`, the provided event becomes the "suspended" event, replacing the /// prior suspended event if there was one. /// /// Only one event can be suspended at a time. If a state machine wants to be triggered for /// multiple events in the future, it is up to that state machine to return the /// (chronologically) next event each time this method is called. /// /// Currently, only the state machine running on the server ever has this method called. /// /// Since they are not associated with a particular player, suspended events trigger /// `process_event` with a `None` as the player in the [TransitionEvent]. fn suspended_event(&self) -> Option<SuspendedEvent<Self::Transition>> { None } } /// A trait indicating that a struct can be used to create a [StateMachine] for a given type. /// If your [StateMachine] does not need to be initialized with any external data or state, /// implement [std::default::Default] on it to avoid the need for a factory. pub trait StateMachineFactory<State: StateMachine>: Sized + Unpin + 'static + Send { fn create(&mut self) -> State; } /// [StateMachineFactory] implementation that uses the `default` method of the relevant /// [StateMachine] type. #[derive(Default)] struct DefaultStateMachineFactory<State: StateMachine + Default> { _phantom: PhantomData<State>, } impl<State: StateMachine + Default> StateMachineFactory<State> for DefaultStateMachineFactory<State> { fn create(&mut self) -> State { Default::default() } }