layer-system 0.4.0

A system for handling different kinds of events
Documentation
#![deny(missing_docs)]
/*!
A simple, flexible layer system for managing UI states, game modes, and event handling.

Layers process events **top-to-bottom** for `update` and **bottom-to-top** for `passive_update`.

Key features:
- Easy stacking/replacing/removing of layers via `Change`.
- Generic over state `S` and events `E`.
- Efficient for small stacks.
*/

/// A special action for the layer.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ChangeAction {
    /// No special action to the layer.
    None,
    /// Remove the current layer.
    Remove,
    /// Remove all layers.
    Clear,
}

/// The action, that will be done after handling an event by a layer.
pub struct Change<S, E> {
    /// Add new layers on top of the current layer.
    add: Box<[Box<dyn Layer<S, E>>]>,
    /// Special actions.
    action: ChangeAction,
    /// Pass the event to the next layer.
    pass: bool,
}

impl<S, E> Change<S, E> {
    /// A simple change doing nothing.
    pub fn none() -> Self {
        Self {
            add: [].into(),
            action: ChangeAction::None,
            pass: false,
        }
    }

    /// A change passing the event to the next layer.
    pub fn pass() -> Self {
        Self {
            add: [].into(),
            action: ChangeAction::None,
            pass: true,
        }
    }

    /// A change adding new layers.
    pub fn add(add: Box<[Box<dyn Layer<S, E>>]>) -> Self {
        Self {
            add,
            action: ChangeAction::None,
            pass: false,
        }
    }

    /// A change adding a single new layer.
    pub fn add_single(add: Box<dyn Layer<S, E>>) -> Self {
        Self {
            add: [add].into(),
            action: ChangeAction::None,
            pass: false,
        }
    }

    /// A simple change removing the current layer.
    pub fn remove() -> Self {
        Self {
            add: [].into(),
            action: ChangeAction::Remove,
            pass: false,
        }
    }

    /// A change replacing the current layer with new layers.
    pub fn replace(add: Box<[Box<dyn Layer<S, E>>]>) -> Self {
        Self {
            add,
            action: ChangeAction::Remove,
            pass: false,
        }
    }

    /// A change replacing the current layer with a single new layer.
    pub fn replace_single(add: Box<dyn Layer<S, E>>) -> Self {
        Self {
            add: [add].into(),
            action: ChangeAction::Remove,
            pass: false,
        }
    }

    /// A change removing all layers.
    pub fn close() -> Self {
        Self {
            add: [].into(),
            action: ChangeAction::Clear,
            pass: false,
        }
    }

    /// A change replacing all layers with a new stack of layers.
    pub fn clear(add: Box<[Box<dyn Layer<S, E>>]>) -> Self {
        Self {
            add,
            action: ChangeAction::Clear,
            pass: false,
        }
    }

    /// A change replacing all layers with a single new layer.
    pub fn clear_single(add: Box<dyn Layer<S, E>>) -> Self {
        Self {
            add: [add].into(),
            action: ChangeAction::Clear,
            pass: false,
        }
    }
}

/// A trait, every layer has to implement, in order to be used by the layer manager;
pub trait Layer<S, E> {
    /// Executed for all layers from bottom to top. Most useful for rendering.
    fn passive_update(&mut self, _state: &mut S, _event: &E) {}

    /// Executed for top layer and optionally for more layers. Most useful for click events.
    fn update(&mut self, _state: &mut S, _event: &E) -> Change<S, E>;
}

/// The layer manager deals with the layers you create.
pub struct LayerManager<S, E> {
    layers: Vec<Box<dyn Layer<S, E>>>,
}

impl<S, E> LayerManager<S, E> {
    /// Create a new layer manager containing specified initial layers.
    pub fn new(layers: Vec<Box<dyn Layer<S, E>>>) -> Self {
        Self { layers }
    }

    /// Checks if the layer manager is still active. When not active, the program should terminate or new layers should be added before calling `update` again.
    pub fn is_active(&self) -> bool {
        !self.layers.is_empty()
    }

    /// Everytime the program recieves or generates an event, which should be handled by a layer, this method has to be called.
    pub fn update(&mut self, state: &mut S, event: E) {
        for i in (0..self.layers.len()).rev() {
            let layer = &mut self.layers[i];
            let Change { add, action, pass } = layer.update(state, &event);

            use ChangeAction::*;
            let add_index = match action {
                None => i + 1,
                Remove => {
                    self.layers.remove(i);
                    i
                }
                Clear => {
                    self.layers.clear();
                    0
                }
            };

            for added in add.into_iter().rev() {
                self.layers.insert(add_index, added);
            }

            if !pass {
                break;
            }
        }

        for layer in &mut self.layers {
            layer.passive_update(state, &event);
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::*;

    pub enum Event {
        Idle,
        Input,
        Exit,
    }

    pub struct GlobalState;

    pub struct MainLayer;

    impl Layer<GlobalState, Event> for MainLayer {
        fn update(
            &mut self,
            _state: &mut GlobalState,
            event: &Event,
        ) -> Change<GlobalState, Event> {
            match event {
                Event::Input => Change::add_single(Box::new(TopLayer)),
                Event::Idle => Change::none(),
                Event::Exit => Change::remove(),
            }
        }
    }

    pub struct TopLayer;

    impl Layer<GlobalState, Event> for TopLayer {
        fn update(
            &mut self,
            _state: &mut GlobalState,
            event: &Event,
        ) -> Change<GlobalState, Event> {
            match event {
                Event::Input => Change::pass(),
                Event::Idle => Change::none(),
                Event::Exit => Change::remove(),
            }
        }
    }

    #[test]
    fn example() {
        let mut manager = LayerManager::new(vec![Box::new(MainLayer), Box::new(TopLayer)]);
        let mut state = GlobalState;

        manager.update(&mut state, Event::Idle);
        manager.update(&mut state, Event::Input);
        manager.update(&mut state, Event::Idle);

        manager.update(&mut state, Event::Exit);
        assert_eq!(manager.layers.len(), 2);
        assert!(manager.is_active());

        manager.update(&mut state, Event::Exit);
        assert_eq!(manager.layers.len(), 1);
        assert!(manager.is_active());

        manager.update(&mut state, Event::Exit);
        assert!(manager.layers.is_empty());
        assert!(!manager.is_active());
    }
}