[−][src]Struct mode::Automaton
Represents a state machine over a set of Mode
s 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 Mode
s 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
Mode
s 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)
[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.
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> 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> 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> 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,
Auto Trait Implementations
Blanket Implementations
impl<T, U> Into for T where
U: From<T>,
[src]
U: From<T>,
impl<T> ToString for T where
T: Display + ?Sized,
[src]
T: Display + ?Sized,
impl<T> From for T
[src]
impl<T, U> TryFrom for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = !
try_from
)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
try_from
)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,