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 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
// Copyright 2019 Andrew Thomas Christensen // // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the // MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. This file may not be copied, // modified, or distributed except according to those terms. use crate::Transition; /// Trait that represents a state within an `Automaton`. /// /// Every `Automaton` contains a single `Mode` instance that represents the active state of the state machine. An /// `Automaton<Base>` can **only** switch between implementations of `Mode` of the same `Base` type. The `Automaton` /// only allows its active `Mode` to be accessed as a `Base` reference, so only functions exposed on the `Base` type are /// callable on the `Mode` from outside the `Automaton`. /// /// See [`Automaton`](struct.Automaton.html) for more details. /// /// # Transitions /// `Mode`s can choose to transition to any other `Mode` with the same `Base` type. This is accomplished by returning a /// `Transition` function from the `get_transition()` function, which will cause the parent `Automaton` to switch to /// another `Mode` the next time `perform_transitions()` is called. /// /// See [`Transition`](trait.Transition.html) and /// [`Automaton::perform_transitions()`](struct.Automaton.html#method.perform_transitions) for more details. /// /// # Usage /// ``` /// use mode::*; /// /// trait MyMode { /// // TODO: Define some common interface for ModeA and ModeB. /// } /// /// struct ModeA; // TODO: Add fields. /// impl MyMode for ModeA { } /// /// impl Mode for ModeA { /// type Base = MyMode; /// fn as_base(&self) -> &Self::Base { self } /// fn as_base_mut(&mut self) -> &mut Self::Base { self } /// fn get_transition(&mut self) -> Option<Box<Transition<Self>>> { /// // Transition to ModeB. ModeA can swap to ModeB because both share the same Base. /// Some(Box::new(|previous : Self| { ModeB })) /// } /// } /// /// struct ModeB; // TODO: Add fields. /// impl MyMode for ModeB { } /// /// impl Mode for ModeB { /// type Base = MyMode; /// fn as_base(&self) -> &Self::Base { self } /// fn as_base_mut(&mut self) -> &mut Self::Base { self } /// fn get_transition(&mut self) -> Option<Box<Transition<Self>>> { None } // None means don't transition. /// } /// ``` /// /// # The `Base` parameter /// You will notice from the [example](#usage) above that `ModeA` and `ModeB` implement `Mode` and `MyMode` separately, /// but the `MyMode` trait itself does **not** extend `Mode`, i.e. is defined as `trait MyMode` as opposed to /// `trait MyMode : Mode<Base = MyMode>`. We want to use `MyMode` as the `Base` type for `ModeA` and `ModeB`, but /// unfortunately having `MyMode` extend `Mode<Base = MyMode>` would create a circular dependency between the two types, /// and would cause a compile error. Hence, while it is possible to cast `ModeA` or `ModeB` to `MyMode` or `Mode`, /// casting between `MyMode` and `Mode` is not allowed. /// /// # `as_base()` and `as_base_mut()` /// As mentioned above, a `Mode` reference **cannot** be cast to its `Base` type. What's more, the `Automaton` can only /// require that the current `Mode` implements `Mode<Base = Base>`, and **cannot** enforce that it is also convertible /// to `Base`. That's because `Base` is a type parameter and not a trait, and therefore **cannot** be used as a /// constraint in `where` clauses, e.g. `where T : Base`. /// /// Since the `Automaton` needs to be able to return a `Base` reference to the current `Mode`, each `Mode` is required /// to implement `as_base()` and `as_base_mut()` functions that return `self` as a `&Base` and a `&mut Base`, /// respectively. Unfortunately, these functions have to be defined manually for each struct that implements `Mode`. /// /// **NOTE:** This may change when [`Unsize`](https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md) /// becomes stable, since it will provide a way for `struct`s to express that a generic parameter must be convertible to /// a particular type. /// pub trait Mode : 'static { /// Represents the user-facing interface for the `Mode` that will be exposed via the `Automaton`. In order to be /// used with an `Automaton`, the `Base` type of the `Mode` **must** match the `Base` type of the `Automaton`. This /// is so that the `Automaton` can provide `get_mode()` and `get_mode_mut()` functions that return a reference to /// the `Mode` as the `Base` type. /// type Base : ?Sized; /// Returns an immutable reference to this `Mode` as a `&Self::Base`. /// fn as_base(&self) -> &Self::Base; /// Returns a mutable reference to this `Mode` as a `&mut Self::Base`. /// fn as_base_mut(&mut self) -> &mut Self::Base; /// Every time `perform_transitions()` is called on an `Automaton`, This function will be called on the current /// `Mode` to determine whether it wants another `Mode` to become active. If this function returns `None`, the /// current `Mode` will remain active. If it returns a valid `Transition` function, however, the `Automaton` will /// call the function on the active `Mode`, consuming it and swapping in whichever `Mode` is produced as a result. /// /// See [`Transition`](trait.Transition.html) for more details. /// fn get_transition(&mut self) -> Option<Box<Transition<Self>>>; }