├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── examples └── simple.rs └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | sudo: false 3 | 4 | addons: 5 | apt: 6 | packages: 7 | - libcurl4-openssl-dev 8 | - libelf-dev 9 | - libdw-dev 10 | 11 | rust: 12 | - nightly 13 | - stable 14 | - beta 15 | 16 | before_script: 17 | - | 18 | pip install 'travis-cargo<0.2' --user && 19 | export PATH=$HOME/.local/bin:$PATH 20 | 21 | script: 22 | - | 23 | travis-cargo build && 24 | travis-cargo test && 25 | travis-cargo --only stable doc 26 | after_success: 27 | - travis-cargo --only stable doc-upload 28 | - travis-cargo coveralls --no-sudo 29 | 30 | env: 31 | global: 32 | - TRAVIS_CARGO_NIGHTLY_FEATURE="" 33 | - secure: "T0Xhg/g00jd770P62O/VemKPEv98NLXDqOGVZw1c8hubUDHeZLWuRHPv4n+qLXmCg80gRe5ASF4xmUoxeB9JIYOb+tqZ7Ek7f/OGmFwP5+Kr9YaZMRu69DPueZmc1Q8MT6SkTFDG4WvaMzdz6UfwyLs7MCcwHu3bYAOuD0oPEMo=" 34 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 1.0.0 - 2016-01-15 2 | 3 | * Stable release 4 | 5 | ### 0.1.0 - 2015-06-13 6 | 7 | * Initial release 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "microstate" 4 | version = "1.0.0" 5 | authors = ["Jan-Erik Rediger "] 6 | 7 | keywords = ["statemachine"] 8 | description = "Finite state machine, inspired by micromachine" 9 | 10 | readme = "README.md" 11 | license = "MIT" 12 | 13 | homepage = "https://github.com/badboy/microstate" 14 | documentation = "https://badboy.github.io/microstate" 15 | repository = "https://github.com/badboy/microstate" 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jan-Erik Rediger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MicroState 2 | ========= 3 | 4 | [![Build Status](https://travis-ci.org/badboy/microstate.svg?branch=master)](https://travis-ci.org/badboy/microstate) 5 | [![crates.io](http://meritbadge.herokuapp.com/microstate)](https://crates.io/crates/microstate) 6 | 7 | Minimal Finite State Machine. 8 | 9 | Description 10 | ----------- 11 | 12 | A finite state machine is in only one state at a time. 13 | From there it can change from one state to another when initiated by an triggering event: the transition. 14 | A finite state machine is fully defined by a list of states and the transitions triggering a change from one state to another. 15 | 16 | And that's all this crate does: it lets you define the states and transitions. 17 | The rest is up to you. 18 | 19 | Inspired by [@soveran](https://twitter.com/soveran)'s [micromachine](https://github.com/soveran/micromachine) in Ruby. 20 | 21 | Documentation 22 | ------------- 23 | 24 | [Online documentation](http://badboy.github.io/microstate/microstate) 25 | 26 | Usage 27 | ----- 28 | 29 | First you need to import the macro: 30 | 31 | ```rust 32 | #[macro_use] extern crate microstate; 33 | ``` 34 | 35 | You can then create a new state machine and call transitions. 36 | 37 | ```rust 38 | microstate!{ 39 | MicroMachine { New }; 40 | states { New, Confirmed, Ignored }; 41 | 42 | confirm { 43 | New => Confirmed 44 | } 45 | 46 | ignore { 47 | New => Ignored 48 | } 49 | 50 | reset { 51 | Confirmed => New 52 | Ignored => New 53 | } 54 | } 55 | 56 | let mut machine = MicroMachine::new(); 57 | 58 | machine.confirm(); // => Some(Confirmed) 59 | machine.state(); // => Confirmed 60 | 61 | machine.ignore(); // => None 62 | machine.state(); // => Confirmed 63 | 64 | machine.reset(); // => Some(New) 65 | machine.state(); // => New 66 | 67 | machine.ignore(); // => Some(Ignored) 68 | machine.state(); // => Ignored 69 | ``` 70 | 71 | ## Contribute 72 | 73 | If you find bugs or want to help otherwise, please [open an issue](https://github.com/badboy/microstate/issues). 74 | 75 | ## License 76 | 77 | MIT. See [LICENSE](LICENSE). 78 | -------------------------------------------------------------------------------- /examples/simple.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate microstate; 3 | 4 | microstate!{ 5 | MicroMachine { New } 6 | states { New, Confirmed, Ignored } 7 | 8 | confirm { 9 | New => Confirmed 10 | } 11 | 12 | ignore { 13 | New => Ignored 14 | } 15 | 16 | reset { 17 | Confirmed => New 18 | Ignored => New 19 | } 20 | } 21 | 22 | fn main() { 23 | let mut machine = MicroMachine::new(); 24 | 25 | println!("{:?}", machine.confirm()); 26 | println!("{:?}", machine.state()); 27 | 28 | println!("{:?}", machine.ignore()); 29 | println!("{:?}", machine.state()); 30 | 31 | println!("{:?}", machine.reset()); 32 | println!("{:?}", machine.state()); 33 | 34 | println!("{:?}", machine.ignore()); 35 | println!("{:?}", machine.state()); 36 | } 37 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! MicroState 2 | //! 3 | //! A minimal Finite State Machine. 4 | //! 5 | //! Example: 6 | //! 7 | //! ``` 8 | //! #[macro_use] extern crate microstate; 9 | //! microstate! { 10 | //! Simple { A } 11 | //! states { A, B } 12 | //! 13 | //! next { 14 | //! A => B 15 | //! B => A 16 | //! } 17 | //! } 18 | //! 19 | //! # fn main() { 20 | //! use Simple::State::*; 21 | //! 22 | //! let mut machine = Simple::new(); 23 | //! assert_eq!(A, machine.state()); 24 | //! assert_eq!(Some(B), machine.next()); 25 | //! assert_eq!(Some(A), machine.next()); 26 | //! # } 27 | //! ``` 28 | 29 | /// Create a new state machine 30 | /// 31 | /// It takes a name, the initial value, all possible states 32 | /// and the transitions. 33 | /// 34 | /// See the main documentation for a proper example. 35 | #[macro_export] 36 | macro_rules! microstate ( 37 | ( 38 | $machine:ident { $initial:ident } 39 | states { $($states:ident),* } 40 | 41 | $($meth:ident { 42 | $($from:ident => $to:ident)* 43 | })* 44 | ) => ( 45 | #[allow(non_snake_case)] 46 | pub mod $machine { 47 | #[derive(Clone,PartialEq,Eq,Debug)] 48 | pub enum State { 49 | #[doc(hidden)] 50 | __InvalidState__, // Just be able to match _ further down 51 | $($states),* 52 | } 53 | #[derive(PartialEq,Eq,Debug)] 54 | pub struct Machine { 55 | state: State, 56 | } 57 | 58 | pub fn new() -> Machine { 59 | Machine::new() 60 | } 61 | 62 | impl Machine { 63 | pub fn new() -> Machine { 64 | Machine { 65 | state: State::$initial 66 | } 67 | } 68 | 69 | pub fn state(&self) -> State { 70 | self.state.clone() 71 | } 72 | 73 | $(pub fn $meth(&mut self) -> Option { 74 | match self.state { 75 | $( State::$from => { self.state = State::$to; Some(State::$to) } ),* 76 | _ => None 77 | } 78 | })* 79 | } 80 | } 81 | )); 82 | 83 | #[cfg(test)] 84 | mod tests { 85 | microstate!{ 86 | Micro { New } 87 | states { New, Confirmed, Ignored } 88 | 89 | confirm { 90 | New => Confirmed 91 | } 92 | 93 | ignore { 94 | New => Ignored 95 | } 96 | 97 | reset { 98 | Confirmed => New 99 | Ignored => New 100 | } 101 | } 102 | use self::Micro::State::*; 103 | 104 | #[test] 105 | fn test_transition_works() { 106 | let mut machine = Micro::new(); 107 | 108 | assert_eq!(New, machine.state()); 109 | 110 | assert_eq!(Some(Confirmed), machine.confirm()); 111 | assert_eq!(Confirmed, machine.state()); 112 | 113 | assert_eq!(None, machine.ignore()); 114 | assert_eq!(Confirmed, machine.state()); 115 | 116 | assert_eq!(Some(New), machine.reset()); 117 | assert_eq!(New, machine.state()); 118 | 119 | assert_eq!(Some(Ignored), machine.ignore()); 120 | assert_eq!(Ignored, machine.state()); 121 | } 122 | } 123 | --------------------------------------------------------------------------------