use crate::*; /// A collection of input bindings. /// /// Each contained layer defines a mapping from input event to command invocation /// over a given state. Furthermore, each layer may have an associated condition, /// so that only certain layers are active at a given time depending on state. #[derive(Default, Debug)] pub struct InputLayers(Vec); /// A single input binding layer. #[derive(Default, Debug)] struct InputLayer { condition: Option, bindings: Ast, } impl InputLayers { /// Create an input map with a single non-conditional layer. /// (Use [Default::default] to get an empty map.) pub fn new (layer: Ast) -> Self { Self::default().layer(layer) } /// Add layer, return `Self`. pub fn layer (mut self, layer: Ast) -> Self { self.add_layer(layer); self } /// Add conditional layer, return `Self`. pub fn layer_if (mut self, condition: Ast, layer: Ast) -> Self { self.add_layer_if(Some(condition), layer); self } /// Add layer, return `&mut Self`. pub fn add_layer (&mut self, layer: Ast) -> &mut Self { self.add_layer_if(None, layer.into()); self } /// Add conditional layer, return `&mut Self`. pub fn add_layer_if (&mut self, condition: Option, bindings: Ast) -> &mut Self { self.0.push(InputLayer { condition, bindings }); self } /// Evaluate the active layers for a given state, /// returning the command to be executed, if any. pub fn handle (&self, state: &mut S, input: I) -> Perhaps where S: Eval + Eval, I: Eval, O: Command { let layers = self.0.as_slice(); for InputLayer { condition, bindings } in layers.iter() { let mut matches = true; if let Some(condition) = condition { matches = state.eval(condition.clone(), ||"input: no condition")?; } if matches && let Some(exp) = bindings.0.exp_head() && input.eval(Ast(exp.clone()), ||"InputLayers: input.eval(binding) failed")? && let Some(command) = state.try_eval(exp)? { return Ok(Some(command)) } } Ok(None) } }