use std::collections::HashMap;
use std::fmt::{self, Display};
use std::slice::Iter;
use crate::inputs::key::Key;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Action {
Quit,
}
impl Action {
pub fn iterator() -> Iter<'static, Action> {
static ACTIONS: [Action; 1] = [
Action::Quit,
];
ACTIONS.iter()
}
pub fn keys(&self) -> &[Key] {
match self {
Action::Quit => &[Key::Ctrl('c'), Key::Char('q')],
}
}
}
impl Display for Action {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let str = match self {
Action::Quit => "Quit",
};
write!(f, "{}", str)
}
}
#[derive(Default, Debug, Clone)]
pub struct Actions(Vec<Action>);
impl Actions {
pub fn find(&self, key: Key) -> Option<&Action> {
Action::iterator()
.filter(|action| self.0.contains(action))
.find(|action| action.keys().contains(&key))
}
pub fn actions(&self) -> &[Action] {
self.0.as_slice()
}
}
impl From<Vec<Action>> for Actions {
fn from(actions: Vec<Action>) -> Self {
let mut map: HashMap<Key, Vec<Action>> = HashMap::new();
for action in actions.iter() {
for key in action.keys().iter() {
match map.get_mut(key) {
Some(vec) => vec.push(*action),
None => {
map.insert(*key, vec![*action]);
}
}
}
}
let errors = map
.iter()
.filter(|(_, actions)| actions.len() > 1) .map(|(key, actions)| {
let actions = actions
.iter()
.map(Action::to_string)
.collect::<Vec<_>>()
.join(", ");
format!("Conflict key {} with actions {}", key, actions)
})
.collect::<Vec<_>>();
if !errors.is_empty() {
panic!("{}", errors.join("; "))
}
Self(actions)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_find_action_by_key() {
let actions: Actions = vec![Action::Quit].into();
let result = actions.find(Key::Ctrl('c'));
assert_eq!(result, Some(&Action::Quit));
}
#[test]
fn should_find_action_by_key_not_found() {
let actions: Actions = vec![Action::Quit].into();
let result = actions.find(Key::Alt('w'));
assert_eq!(result, None);
}
#[test]
fn should_create_actions_from_vec() {
let _actions: Actions = vec![
Action::Quit,
]
.into();
}
#[test]
#[should_panic]
fn should_panic_when_create_actions_conflict_key() {
let _actions: Actions = vec![
Action::Quit,
Action::Quit,
]
.into();
}
}