[−][src]Struct mode::Automaton
Represents a state machine over a set of Modes that can be referenced via some common interface Base.
The Automaton contains a single, active Mode that represents the current state of the state machine. The current
Mode is accessible via the borrow_mode() and borrow_mode_mut() functions, which return a Base reference.
Functions and members of the inner Base type can also be accessed directly via the Deref and DerefMut traits.
The Automaton provides a perform_transitions() function that should be called at some point in order to allow
the current Mode to transition another Mode in, if desired.
See Mode::get_transition() for more details.
The 'a lifetime
Most types in this library include an explicit 'a lifetime, which represents the lifetime of the Automaton
wrapping each Mode. In order for a Mode to be used with an Automaton, all references within the Mode must
outlive the parent Automaton. Having this lifetime allows for the creation of Modes that store references to
objects that outlive the Automaton but are still declared on the stack. (See example below.)
Example
use mode::*; struct IncrementMode<'a> { pub number : &'a mut u32, pub step : u32, } impl<'a> IncrementMode<'a> { fn update(&mut self) { *self.number += self.step } fn get_step(&self) -> u32 { self.step } } impl<'a> Mode<'a> for IncrementMode<'a> { type Base = Self; fn as_base(&self) -> &Self::Base { self } fn as_base_mut(&mut self) -> &mut Self::Base { self } fn get_transition(&mut self) -> Option<TransitionBox<'a, Self>> { if self.step > 0 { // Transition to another IncrementMode with a lower step amount. Some(Box::new(|previous : Self| { IncrementMode { number: previous.number, step: previous.step - 1 } })) } else { None } // None means don't transition } } // Create a shared counter and pass it into the Mode. let mut number : u32 = 0; // NOTE: The Automaton can't outlive our shared counter. { let mut automaton = Automaton::with_initial_mode(IncrementMode { number: &mut number, step: 10 }); // NOTE: Automaton implements Deref so that all Base functions can be called // through an Automaton reference. while automaton.get_step() > 0 { // Update the current Mode. automaton.update(); // Let the Automaton handle transitions. automaton.perform_transitions(); } } // Make sure we got the right result. assert_eq!(number, 55);
The Base parameter
The Base parameter may be either a trait (e.g. Automaton<dyn SomeTrait>) or a concrete type
(e.g. Automaton<SomeStructThatImplsMode>). Given a trait, the Automaton will be able to swap between any
Modes that implement the trait. However, this means that the Automaton will only allow the inner Mode to
be borrowed via a trait reference, implying that only functions defined on the trait will be callable.
By contrast, if given a struct, all functions defined on the inner type will be accessible from outside the
Automaton. However, this also implies that the Automaton will only be able to switch between states of the
same concrete type.
For more on the Base parameter, see Mode.
Usage
use mode::*; // Use with_initial_mode() to create the Automaton with an initial state. let mut automaton = Automaton::with_initial_mode(SomeMode); // Functions can be called on the inner Mode through an Automaton reference // via the Deref and DerefMut traits automaton.some_fn(); automaton.some_mut_fn(); // If you want to be more explicit, use borrow_mode() or borrow_mode_mut(); automaton.borrow_mode().some_fn(); automaton.borrow_mode_mut().some_mut_fn(); // Let the Automaton handle transitions. automaton.perform_transitions();
Methods
impl<'a, Base: ?Sized> Automaton<'a, Base> where
Base: 'a, [src]
Base: 'a,
pub fn with_initial_mode<M>(initial_mode: M) -> Self where
M: 'a + Mode<'a, Base = Base>, [src]
M: 'a + Mode<'a, Base = Base>,
Creates a new Automaton with the specified initial_mode, which will be the active Mode for the Automaton
that is returned.
pub fn perform_transitions(&mut self) -> bool[src]
Calls get_transition() on the current Mode to determine whether it wants to transition out. If a
Transition is returned, the Transition callback will be called on the current Mode, swapping in whichever
Mode it returns as a result.
For convenience, this function returns a bool representing whether a Transition was performed or not. A
result of true indicates that the Automaton transitioned to another Mode. If no Transition was performed
and the previous Mode is still active, returns false.
See Transition and
Mode::get_transition() for more details.
pub fn borrow_mode(&self) -> &Base[src]
Returns an immutable reference to the current Mode as a &Self::Base, allowing immutable functions to be
called on the inner Mode.
NOTE: Automaton also implements Deref<Target = Base>, allowing all Base members to be accessed via a
reference to the Automaton. Hence, you can usually leave the borrow_mode() out and simply treat the
Automaton as if it were an object of type Base.
pub fn borrow_mode_mut(&mut self) -> &mut Base[src]
Returns a mutable reference to the current Mode as a &mut Self::Base, allowing mutable functions to be
called on the inner Mode.
NOTE: Automaton also implements Deref<Target = Base>, allowing all Base members to be accessed via a
reference to the Automaton. Hence, you can usually leave the borrow_mode_mut() out and simply treat the
Automaton as if it were an object of type Base.
impl<'a, Base> Automaton<'a, Base> where
Base: 'a + Mode<'a, Base = Base> + Default, [src]
Base: 'a + Mode<'a, Base = Base> + Default,
pub fn new() -> Self[src]
Creates a new Automaton with a default Mode instance as the active Mode.
NOTE: This only applies if Base is a concrete type (e.g. Automaton<SomeStructThatImplsMode>) that
implements Default. If Base is a trait type (e.g. Automaton<dyn SomeTraitThatExtendsMode>) or you
would otherwise like to specify the initial mode of the created Automaton, use
with_initial_mode() instead.
use mode::*; struct ConcreteMode { count : u32 }; impl<'a> Mode<'a> for ConcreteMode { type Base = Self; fn as_base(&self) -> &Self { self } fn as_base_mut(&mut self) -> &mut Self { self } fn get_transition(&mut self) -> Option<TransitionBox<'a, Self>> { // TODO: Logic for transitioning between states goes here. Some(Box::new( |previous : Self| { ConcreteMode { count: previous.count + 1 } })) } } impl Default for ConcreteMode { fn default() -> Self { ConcreteMode { count: 0 } } } // Create an Automaton with a default Mode. // NOTE: Deref coercion allows us to access the CounterMode's count variable // through an Automaton reference. let mut automaton = Automaton::<ConcreteMode>::new(); assert!(automaton.count == 0); // Keep transitioning the current Mode out until we reach the target state // (i.e. a count of 10). while automaton.count < 10 { automaton.perform_transitions(); }
Trait Implementations
impl<'a, Base> Default for Automaton<'a, Base> where
Base: 'a + Mode<'a, Base = Base> + Default, [src]
Base: 'a + Mode<'a, Base = Base> + Default,
fn default() -> Self[src]
Creates a new Automaton with the default Mode active. This is equivalent to calling Automaton::new().
See note on new() for more on when this function can be used.
impl<'a, Base: ?Sized> Deref for Automaton<'a, Base> where
Base: 'a, [src]
Base: 'a,
type Target = Base
The resulting type after dereferencing.
fn deref(&self) -> &Base[src]
Returns an immutable reference to the current Mode as a &Self::Base, allowing immutable functions to be
called on the inner Mode.
impl<'a, Base: ?Sized> DerefMut for Automaton<'a, Base> where
Base: 'a, [src]
Base: 'a,
fn deref_mut(&mut self) -> &mut Base[src]
Returns a mutable reference to the current Mode as a &mut Self::Base, allowing mutable functions to be
called on the inner Mode.
impl<'a, Base: ?Sized> Debug for Automaton<'a, Base> where
Base: 'a + Debug, [src]
Base: 'a + Debug,
If Base implements std::fmt::Debug, Automaton also implements Debug, and will print the current_mode.
Usage
use mode::*; use std::fmt; trait MyBase : fmt::Debug { } // TODO: Add common interface. #[derive(Debug)] struct MyMode { pub foo : i32, pub bar : &'static str, } impl MyBase for MyMode { } // TODO: Implement common interface. impl<'a> Mode<'a> for MyMode { type Base = MyBase + 'a; fn as_base(&self) -> &Self::Base { self } fn as_base_mut(&mut self) -> &mut Self::Base { self } fn get_transition(&mut self) -> Option<TransitionBox<'a, Self>> { None } // TODO } let automaton = Automaton::with_initial_mode(MyMode { foo: 3, bar: "Hello, World!" }); dbg!(automaton);
impl<'a, Base: ?Sized> Display for Automaton<'a, Base> where
Base: 'a + Display, [src]
Base: 'a + Display,
impl<'a, Base: ?Sized> Borrow<Base> for Automaton<'a, Base> where
Base: 'a, [src]
Base: 'a,
impl<'a, Base: ?Sized> BorrowMut<Base> for Automaton<'a, Base> where
Base: 'a, [src]
Base: 'a,
fn borrow_mut(&mut self) -> &mut Base[src]
Returns a mutable reference to the current Mode as a &mut Self::Base.
Auto Trait Implementations
Blanket Implementations
impl<T> ToString for T where
T: Display + ?Sized, [src]
T: Display + ?Sized,
impl<T, U> Into for T where
U: From<T>, [src]
U: From<T>,
impl<T> From for T[src]
impl<T, U> TryFrom for T where
U: Into<T>, [src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>[src]
impl<T> Borrow for T where
T: ?Sized, [src]
T: ?Sized,
impl<T> BorrowMut for T where
T: ?Sized, [src]
T: ?Sized,
fn borrow_mut(&mut self) -> &mut T[src]
impl<T, U> TryInto for T where
U: TryFrom<T>, [src]
U: TryFrom<T>,
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>[src]
impl<T> Any for T where
T: 'static + ?Sized, [src]
T: 'static + ?Sized,