mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
73 lines
2.6 KiB
Rust
73 lines
2.6 KiB
Rust
use crate::*;
|
|
|
|
pub struct EventMap<'a, S, I: PartialEq, C> {
|
|
pub bindings: &'a [(I, &'a dyn Fn(&S) -> Option<C>)],
|
|
pub fallback: Option<&'a dyn Fn(&S, &I) -> Option<C>>
|
|
}
|
|
|
|
impl<'a, S, I: PartialEq, C> EventMap<'a, S, I, C> {
|
|
pub fn handle (&self, state: &S, input: &I) -> Option<C> {
|
|
for (binding, handler) in self.bindings.iter() {
|
|
if input == binding {
|
|
return handler(state)
|
|
}
|
|
}
|
|
if let Some(fallback) = self.fallback {
|
|
fallback(state, input)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
#[macro_export] macro_rules! keymap {
|
|
(
|
|
$(<$lt:lifetime>)? $KEYS:ident = |$state:ident: $State:ty, $input:ident: $Input:ty| $Command:ty
|
|
{ $($key:expr => $handler:expr),* $(,)? } $(,)?
|
|
) => {
|
|
pub const $KEYS: EventMap<'static, $State, $Input, $Command> = EventMap {
|
|
fallback: None,
|
|
bindings: &[ $(($key, &|$state|Some($handler)),)* ]
|
|
};
|
|
input_to_command!($(<$lt>)? $Command: |$state: $State, input: $Input|$KEYS.handle($state, input)?);
|
|
};
|
|
(
|
|
$(<$lt:lifetime>)? $KEYS:ident = |$state:ident: $State:ty, $input:ident: $Input:ty| $Command:ty
|
|
{ $($key:expr => $handler:expr),* $(,)? }, $default:expr
|
|
) => {
|
|
pub const $KEYS: EventMap<'static, $State, $Input, $Command> = EventMap {
|
|
fallback: Some(&|$state, $input|Some($default)),
|
|
bindings: &[ $(($key, &|$state|Some($handler)),)* ]
|
|
};
|
|
input_to_command!($(<$lt>)? $Command: |$state: $State, input: $Input|$KEYS.handle($state, input)?);
|
|
};
|
|
}
|
|
#[macro_export] macro_rules! input_to_command {
|
|
(<$($l:lifetime),+> $Command:ty: |$state:ident:$State:ty, $input:ident:$Input:ty| $handler:expr) => {
|
|
impl<$($l),+> InputToCommand<$Input, $State> for $Command {
|
|
fn input_to_command ($state: &$State, $input: &$Input) -> Option<Self> {
|
|
Some($handler)
|
|
}
|
|
}
|
|
};
|
|
($Command:ty: |$state:ident:$State:ty, $input:ident:$Input:ty| $handler:expr) => {
|
|
impl InputToCommand<$Input, $State> for $Command {
|
|
fn input_to_command ($state: &$State, $input: &$Input) -> Option<Self> {
|
|
Some($handler)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait InputToCommand<I, S>: Command<S> + Sized {
|
|
fn input_to_command (state: &S, input: &I) -> Option<Self>;
|
|
fn execute_with_state (state: &mut S, input: &I) -> Perhaps<bool> {
|
|
Ok(if let Some(command) = Self::input_to_command(state, input) {
|
|
let _undo = command.execute(state)?;
|
|
Some(true)
|
|
} else {
|
|
None
|
|
})
|
|
}
|
|
}
|
|
|