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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
// 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::{Automaton, Mode}; /// A meta-`trait` defining the common `Base` type and `Mode` storage conventions used by a related group of `Mode` /// implementations. `Mode`s can **only** transition to other `Mode`s within the same `Family`, i.e. where both `Mode`s /// share the same `Family` associated `type`. /// /// # The `Base` type /// The `Base` associated type may be either a `dyn Trait` or a concrete type that represents how the current `Mode` can /// be accessed from outside the `Automaton`. /// /// If given some `dyn Trait`, **only** functions common to the `trait` interface will be callable on the current /// `Mode`, as the `Automaton` will **only** allow it to be borrowed via a `trait` reference. However, the `Automaton` /// will allow swapping between different concrete implementations of this common interface, provided that the `Mode` /// associated `type` is a pointer of some kind (e.g. `Box`) and they share the same `Family` associated `type`. /// /// If given a concrete type, e.g. an `enum` or `struct`, **all** functions and members defined on the inner type will /// be accessible from outside the `Automaton`. However, this also implies that **all** states in the `Automaton` will /// be represented by instances of this same concrete type. /// /// # Usage /// To define a new `Family` of `Mode`s, simply define a new unit `struct` and `impl Family` for it. This will allow the /// associated `type`s within `Family` to be defined for that specific `struct`, with the `struct` representing the /// common usage pattern of all `Mode`s with a `Family` associated `type` equal to that `struct`. (See examples below.) /// /// ## A `Family` where `Base` is a concrete type /// ``` /// use mode::{Family, Mode}; /// /// enum SomeMode { A, B, C } /// /// impl Mode for SomeMode { /// type Family = SomeFamily; /// } /// /// impl SomeMode { /// pub fn swap(self) -> Self { /// match self { /// Self::A => Self::B, /// Self::B => Self::C, /// Self::C => Self::A, /// } /// } /// } /// /// struct SomeFamily; /// /// impl Family for SomeFamily { /// type Base = SomeMode; // All SomeFamily Modes will be visible as SomeMode from outside the Automaton. /// type Mode = SomeMode; // The current Mode in the Automaton will be stored as a SomeMode in-place. /// } /// ``` /// /// ## A `Family` where `Base` is a `dyn Trait` /// ``` /// use mode::{Mode, Family}; /// /// trait SomeTrait : Mode<Family = SomeFamily> { /// // ... /// } /// /// struct SomeFamily; /// /// impl Family for SomeFamily { /// type Base = dyn SomeTrait; // All SomeFamily Modes will expose their SomeTrait interface via the Automaton. /// type Mode = Box<dyn SomeTrait>; // The current Mode in the Automaton will be stored as a Box<dyn SomeTrait>. /// } /// ``` /// pub trait Family { /// The user-facing interface for the `Mode` that will be exposed via the `Automaton::borrow_mode()` and /// `Automaton::borrow_mode_mut()` functions. This can be either a concrete type or a `dyn Trait`, depending on /// whether `Self::Mode` is a pointer type or not. /// /// **NOTE:** This is **not** the actual type that will be stored in `Automaton`. This is just the public interface /// for the current `Mode` that will be exposed by the `Automaton`. /// type Base : ?Sized; /// The actual type that will be stored in `Automaton` and moved into the `Automaton::next()` function. For a /// `Family` where `Self::Base` is a **concrete** type, this should be set to the **same** type as `Self::Base`. On /// the other hand, if `Self::Base` is a `dyn Trait`, this should usually be set to some pointer type capable of /// storing `Self::Base`, e.g. `Box<Self::Base>` or `Rc<Self::Base>`. /// type Mode : Mode<Family = Self>; /// Convenience function allowing an `Automaton` to be created for this `Family` type. Note that this is shorthand /// for `Automaton::new()`, and therefore `Self::Mode` *must* implement `Default`. See /// [`Automaton::new()`](struct.Automaton.html#method.new) for more details. /// /// # Usage /// ``` /// use mode::*; /// # /// # struct SomeFamily; /// # impl Family for SomeFamily { /// # type Base = ModeWithDefault; /// # type Mode = ModeWithDefault; /// # } /// /// struct ModeWithDefault { count : u32 }; /// /// impl Mode for ModeWithDefault { /// type Family = SomeFamily; /// } /// /// impl Default for ModeWithDefault { /// fn default() -> Self { /// ModeWithDefault { count: 0 } /// } /// } /// /// // Create an Automaton with a default Mode. /// let mut automaton = SomeFamily::automaton(); /// ``` /// fn automaton() -> Automaton<Self> where Self::Mode : Default { Automaton::new() } /// Convenience function that returns a new `Automaton` for this `Family` type with the specified `mode` as current. /// Note that this is shorthand for `Automaton::with_mode()`. See /// [`Automaton::with_mode()`](struct.Automaton.html#method.with_mode) for more details. /// /// # Usage /// ``` /// use mode::*; /// /// struct SomeFamily; /// impl Family for SomeFamily { /// type Base = SomeMode; /// type Mode = SomeMode; /// } /// /// enum SomeMode { A, B, C }; /// /// impl Mode for SomeMode { /// type Family = SomeFamily; /// } /// /// // Create an Automaton with A as the initial Mode. /// let mut automaton = SomeFamily::automaton_with_mode(SomeMode::A); /// ``` /// fn automaton_with_mode(mode : Self::Mode) -> Automaton<Self> { Automaton::with_mode(mode) } }