Skip to content

Commit

Permalink
Merge v0.2.3 into master
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewtc committed Mar 21, 2019
1 parent d41bb1d commit 07ef529
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 38 deletions.
30 changes: 22 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ struct Working {
}

impl Activity for Working {
fn update(&mut self) { self.hours_worked += 1; }
fn update(&mut self) {
println!("Work, work, work...");
self.hours_worked += 1;
}
}

impl<'a> Mode<'a> for Working {
Expand All @@ -47,6 +50,7 @@ impl<'a> Mode<'a> for Working {
// To swap to another Mode, a Transition function is returned, which will consume
// the current Mode and return a new Mode to be swapped in as active.
Some(Box::new(|previous : Self| {
println!("Time for {}!", if previous.hours_worked == 4 { "lunch" } else { "dinner" });
Eating { hours_worked: previous.hours_worked, calories_consumed: 0 }
}))
}
Expand All @@ -60,7 +64,10 @@ struct Eating {
}

impl Activity for Eating {
fn update(&mut self) { self.calories_consumed += 100; } // Yum!
fn update(&mut self) {
println!("Yum!");
self.calories_consumed += 100;
}
}

impl<'a> Mode<'a> for Eating {
Expand All @@ -70,11 +77,11 @@ impl<'a> Mode<'a> for Eating {
fn get_transition(&mut self) -> Option<TransitionBox<'a, Self>> {
if self.calories_consumed >= 500 {
if self.hours_worked >= 8 {
// Time for bed!
println!("Time for bed!");
Some(Box::new(|_ : Self| { Sleeping { hours_rested: 0 } }))
}
else {
// Time to go back to work!
println!("Time to go back to work!");
Some(Box::new(|previous : Self| {
Working { hours_worked: previous.hours_worked }
}))
Expand All @@ -89,7 +96,10 @@ struct Sleeping {
}

impl Activity for Sleeping {
fn update(&mut self) { self.hours_rested += 1; } // ZzZzZzZz...
fn update(&mut self) {
println!("ZzZzZzZz...");
self.hours_rested += 1;
}
}

impl<'a> Mode<'a> for Sleeping {
Expand All @@ -98,7 +108,7 @@ impl<'a> Mode<'a> for Sleeping {
fn as_base_mut(&mut self) -> &mut Self::Base { self }
fn get_transition(&mut self) -> Option<TransitionBox<'a, Self>> {
if self.hours_rested >= 8 {
// Time for breakfast!
println!("Time for breakfast!");
Some(Box::new(|_| { Eating { hours_worked: 0, calories_consumed: 0 } }))
}
else { None }
Expand All @@ -108,7 +118,7 @@ impl<'a> Mode<'a> for Sleeping {
fn main() {
let mut person = Automaton::with_initial_mode(Working { hours_worked: 0 });

for age in (18..100) {
for _age in 18..100 {
// Update the current Mode for the Automaton.
// NOTE: We can call update() on the inner Mode through the Automaton reference,
// due to Deref coercion.
Expand All @@ -132,4 +142,8 @@ at your option.

## Contributing
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as
defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

If you find bugs, please feel free to open an issue on [GitHub](https://github.com/andrewtc/mode/issues)! Otherwise, if
you would like to propose changes to this library, feel free to send me a pull request and I will handle them as best I
can. Thanks!
115 changes: 115 additions & 0 deletions examples/activity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// 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 mode::*;

// This trait will be used as the Base type for the Automaton, defining a common interface
// for all states.
trait Activity {
fn update(&mut self);
}

// Each state in the state machine implements both Activity (the Base type) and Mode.
struct Working {
pub hours_worked : u32,
}

impl Activity for Working {
fn update(&mut self) {
println!("Work, work, work...");
self.hours_worked += 1;
}
}

impl<'a> Mode<'a> for Working {
type Base = Activity + 'a;
fn as_base(&self) -> &Self::Base { self }
fn as_base_mut(&mut self) -> &mut Self::Base { self }

// This function allows the current Mode to swap to another Mode, when ready.
fn get_transition(&mut self) -> Option<TransitionBox<'a, Self>> {
if self.hours_worked == 4 || self.hours_worked >= 8 {
// To swap to another Mode, a Transition function is returned, which will consume
// the current Mode and return a new Mode to be swapped in as active.
Some(Box::new(|previous : Self| {
println!("Time for {}!", if previous.hours_worked == 4 { "lunch" } else { "dinner" });
Eating { hours_worked: previous.hours_worked, calories_consumed: 0 }
}))
}
else { None } // None means don't transition.
}
}

struct Eating {
pub hours_worked : u32,
pub calories_consumed : u32,
}

impl Activity for Eating {
fn update(&mut self) {
println!("Yum!");
self.calories_consumed += 100;
}
}

impl<'a> Mode<'a> for Eating {
type Base = Activity + '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>> {
if self.calories_consumed >= 500 {
if self.hours_worked >= 8 {
println!("Time for bed!");
Some(Box::new(|_ : Self| { Sleeping { hours_rested: 0 } }))
}
else {
println!("Time to go back to work!");
Some(Box::new(|previous : Self| {
Working { hours_worked: previous.hours_worked }
}))
}
}
else { None }
}
}

struct Sleeping {
pub hours_rested : u32,
}

impl Activity for Sleeping {
fn update(&mut self) {
println!("ZzZzZzZz...");
self.hours_rested += 1;
}
}

impl<'a> Mode<'a> for Sleeping {
type Base = Activity + '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>> {
if self.hours_rested >= 8 {
println!("Time for breakfast!");
Some(Box::new(|_| { Eating { hours_worked: 0, calories_consumed: 0 } }))
}
else { None }
}
}

fn main() {
let mut person = Automaton::with_initial_mode(Working { hours_worked: 0 });

for _age in 18..100 {
// Update the current Mode for the Automaton.
// NOTE: We can call update() on the inner Mode through the Automaton reference,
// due to Deref coercion.
person.update();

// Allow the Automaton to switch Modes.
person.perform_transitions();
}
}
48 changes: 26 additions & 22 deletions examples/counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,22 @@
extern crate mode;

use mode::*;
use std::fmt::Debug;

// Defines the public interface of all `Mode`s below.
trait CounterMode {
// Tells the `CounterMode` to update once.
// Defines the public interface of all Modes below.
trait CounterMode : Debug {
// Tells the CounterMode to update once.
fn update(&mut self);

// Returns an `i32` if the program is finished and a final result has been returned.
// Returns an i32 if the program is finished and a final result has been returned.
fn get_result(&self) -> Option<i32> { None }

// Returns true if the current CounterMode has the final result, false otherwise.
fn has_result(&self) -> bool { self.get_result().is_some() }
}

// `CounterMode` that increments a counter value until it reaches the target value.
// CounterMode that increments a counter value until it reaches the target value.
#[derive(Debug)]
struct UpMode {
pub counter : i32,
pub target : i32,
Expand All @@ -27,7 +32,7 @@ impl CounterMode for UpMode {
fn update(&mut self) {
// Increment the counter until it reaches the target value.
self.counter += 1;
println!("+ {}", self.counter);
print!(" {}", self.counter);
}
}

Expand All @@ -50,7 +55,8 @@ impl<'a> Mode<'a> for UpMode {
}
}

// `CounterMode` that decrements a counter value until it reaches the target value.
// CounterMode that decrements a counter value until it reaches the target value.
#[derive(Debug)]
struct DownMode {
pub counter : i32,
pub target : i32,
Expand All @@ -60,7 +66,7 @@ impl CounterMode for DownMode {
fn update(&mut self) {
// Decrement the counter until it reaches the target value.
self.counter -= 1;
println!("- {}", self.counter);
print!(" {}", self.counter);
}
}

Expand Down Expand Up @@ -94,6 +100,7 @@ impl<'a> Mode<'a> for DownMode {
}

// Represents that we've finished counting and have a final result.
#[derive(Debug)]
struct FinishedMode {
result : i32,
}
Expand Down Expand Up @@ -122,21 +129,18 @@ fn main() {
target: 3,
});

loop {
// Update the inner Mode.
{
if let Some(result) = automaton.get_result() {
// If the current mode returns a result, print it and exit the program.
println!("Result: {}", result);
break;
}
else {
// Keep updating the current mode until it wants to transition or we get a result.
automaton.update();
}
}
println!("Starting in {:?}", automaton.borrow_mode());

while !automaton.has_result() {
// Keep updating the current mode until it wants to transition or we get a result.
automaton.update();

// Allow the Automaton to switch to another Mode after updating the current one, if desired.
automaton.perform_transitions();
if automaton.perform_transitions() {
println!();
println!("Switched to {:?}", automaton.borrow_mode());
}
}

println!("FINISHED! Result: {}", automaton.get_result().unwrap());
}
22 changes: 21 additions & 1 deletion src/automaton.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// modified, or distributed except according to those terms.

use crate::{AnyModeWrapper, Mode, ModeWrapper};
use std::fmt;
use std::{borrow::{Borrow, BorrowMut}, fmt};
use std::ops::{Deref, DerefMut};

/// Represents a state machine over a set of `Mode`s that can be referenced via some common interface `Base`.
Expand Down Expand Up @@ -217,6 +217,26 @@ impl<'a, Base> DerefMut for Automaton<'a, Base>
}
}

impl<'a, Base> Borrow<Base> for Automaton<'a, Base>
where Base : 'a + ?Sized
{
/// Returns an immutable reference to the current `Mode` as a `&Self::Base`.
///
fn borrow(&self) -> &Base {
self.current_mode.borrow_mode()
}
}

impl<'a, Base> BorrowMut<Base> for Automaton<'a, Base>
where Base : 'a + ?Sized
{
/// Returns a mutable reference to the current `Mode` as a `&mut Self::Base`.
///
fn borrow_mut(&mut self) -> &mut Base {
self.current_mode.borrow_mode_mut()
}
}

impl<'a, Base> Automaton<'a, Base>
where Base : 'a + Mode<'a, Base = Base> + Default
{
Expand Down
Loading

0 comments on commit 07ef529

Please sign in to comment.