activity/
activity.rs

1// Copyright 2019 Andrew Thomas Christensen
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the
4// MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. This file may not be copied,
5// modified, or distributed except according to those terms.
6
7use mode::{Automaton, Family, Mode};
8
9// This meta-struct represents a group of all Modes that can be used with the same Automaton, i.e. all states in the
10// same state machine. By implementing Family, we can specify the common interface that will be exposed for all states
11// (type Base) and how the current state will be stored in the Automaton (type Mode). The important thing to note is
12// that this struct will never be instantiated. It only exists to group a set of states (Modes) together.
13// 
14struct ActivityFamily;
15
16impl Family for ActivityFamily {
17    // This is the public interface that will be exposed by the Automaton for all Modes in this Family.
18    type Base = dyn Activity;
19
20    // This is the type that will be stored in the Automaton and passed into the Automaton::next() function.
21    type Mode = Box<dyn Activity>;
22}
23
24// This trait defines a common interface for all Modes in ActivityFamily.
25//
26trait Activity : Mode<Family = ActivityFamily> {
27    fn update(self : Box<Self>) -> Box<dyn Activity>;
28}
29
30// Each state in the state machine implements both Activity (the Base type) and Mode.
31//
32struct Working {
33    pub hours_worked : u32,
34}
35
36impl Mode for Working {
37    type Family = ActivityFamily;
38}
39
40impl Activity for Working {
41    // This function updates the Mode and allows it to swap another one in as current, when ready.
42    //
43    fn update(mut self : Box<Self>) -> Box<dyn Activity> {
44        println!("Work, work, work...");
45        self.hours_worked += 1;
46
47        if self.hours_worked == 4 || self.hours_worked >= 8 {
48            // To swap to another Mode, we can return a new, boxed Mode with the same signature as this one. Note that
49            // because this function consumes the input Box<Self>, we can freely move state out of this Mode and into
50            // the new one that will be swapped in.
51            println!("Time for {}!", if self.hours_worked == 4 { "lunch" } else { "dinner" });
52            Box::new(Eating { hours_worked: self.hours_worked, calories_consumed: 0 })
53        }
54        else { self } // Returning self means that this Mode should remain current.
55    }
56}
57
58struct Eating {
59    pub hours_worked : u32,
60    pub calories_consumed : u32,
61}
62
63impl Mode for Eating {
64    type Family = ActivityFamily;
65}
66
67impl Activity for Eating {
68    fn update(mut self : Box<Self>) -> Box<dyn Activity> {
69        println!("Yum!");
70        self.calories_consumed += 100;
71
72        if self.calories_consumed >= 500 {
73            if self.hours_worked >= 8 {
74                println!("Time for bed!");
75                Box::new(Sleeping { hours_rested: 0 })
76            }
77            else {
78                println!("Time to go back to work!");
79                Box::new(Working { hours_worked: self.hours_worked })
80            }
81        }
82        else { self }
83    }
84}
85
86struct Sleeping {
87    pub hours_rested : u32,
88}
89
90impl Mode for Sleeping {
91    type Family = ActivityFamily;
92}
93
94impl Activity for Sleeping {
95    fn update(mut self : Box<Self>) -> Box<dyn Activity> {
96        println!("ZzZzZzZz...");
97        self.hours_rested += 1;
98
99        if self.hours_rested >= 8 {
100            println!("Time for breakfast!");
101            Box::new(Eating { hours_worked: 0, calories_consumed: 0 })
102        }
103        else { self }
104    }
105}
106
107fn main() {
108    let mut person = ActivityFamily::automaton_with_mode(Box::new(Working { hours_worked: 0 }));
109    
110    for _age in 18..100 {
111        // Update the current Mode and/or transition to another Mode, when the current Mode requests it.
112        Automaton::next(&mut person, |current_mode| current_mode.update());
113    }
114}