topaz 0.4.0

A tiny game engine.
Documentation
/*!
# Topaz

Topaz is a tiny game engine. It uses [specs](https://crates.io/crates/specs)
for its ECS. Any frameworks for graphics, sound, UI, etc. are plugin
crates. All Topaz itself provides is a pushdown automaton (a state machine
coupled with a stack.)
*/

extern crate specs;

use std::rc::Rc;
use std::cell::RefCell;

/**
A transition to another `State`.
*/
pub enum Transition {
    ///Switch to another state.
    Switch(Rc<RefCell<State>>),
    ///Push another state.
    Push(Rc<RefCell<State>>),
    ///Pop this state, returning to the parent state.
    Quit,
    ///Quit the engine.
    Pop,
}

/**
All states must implement this trait.
*/
pub trait State {
    fn run(&mut self) -> Transition;
}

/**
The state manager.
*/
pub struct Engine {
    states: Vec<Rc<RefCell<State>>>,
}
impl Engine {
    pub fn new() -> Self {
        Self {
            states: Vec::new()
        }
    }
    
    /**
    Push a state onto the stack.
    */
    pub fn push_state(&mut self, state: Rc<RefCell<State>>) {
        self.states.push(state);
    }
    
    /**
    Run the `Engine`, starting with the state on the top of the stack.
    
    Since this function consumes the `Engine`, it cannot be reused.
    */
    pub fn run(mut self) {
        loop {
            if self.states.len() == 0 { return; }
            let state_cell = self.states[self.states.len()-1].clone();
            let mut state = state_cell.borrow_mut();
            match state.run() {
                Transition::Switch(new_state) => {
                    self.states.pop();
                    self.states.push(new_state);
                },
                Transition::Pop => {
                    self.states.pop();
                },
                Transition::Quit => {
                    return;
                },
                Transition::Push(new_state) => {
                    self.states.push(new_state);
                }
                
            }
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}