#![feature(associated_type_defaults)] #![feature(if_let_guard)] pub(crate) use dizzle::*; #[cfg(test)] mod input_test; /// Event source pub trait Input: Sized { /// Type of input event type Event; /// Result of handling input type Handled; // TODO: make this an Option> containing the undo /// Currently handled event fn event (&self) -> &Self::Event; /// Whether component should exit fn is_done (&self) -> bool; /// Mark component as done fn done (&self); } /// Define a trait an implement it for various mutation-enabled wrapper types. */ #[macro_export] macro_rules! flex_trait_mut ( ($Trait:ident $(<$($A:ident:$T:ident),+>)? { $(fn $fn:ident (&mut $self:ident $(, $arg:ident:$ty:ty)*) -> $ret:ty $body:block)* })=>{ pub trait $Trait $(<$($A: $T),+>)? { $(fn $fn (&mut $self $(,$arg:$ty)*) -> $ret $body)* } impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for &mut _T_ { $(fn $fn (&mut $self $(,$arg:$ty)*) -> $ret { (*$self).$fn($($arg),*) })* } impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for Option<_T_> { $(fn $fn (&mut $self $(,$arg:$ty)*) -> $ret { if let Some(this) = $self { this.$fn($($arg),*) } else { Ok(None) } })* } impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for ::std::sync::Mutex<_T_> { $(fn $fn (&mut $self $(,$arg:$ty)*) -> $ret { $self.get_mut().unwrap().$fn($($arg),*) })* } impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for ::std::sync::Arc<::std::sync::Mutex<_T_>> { $(fn $fn (&mut $self $(,$arg:$ty)*) -> $ret { $self.lock().unwrap().$fn($($arg),*) })* } impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for ::std::sync::RwLock<_T_> { $(fn $fn (&mut $self $(,$arg:$ty)*) -> $ret { $self.write().unwrap().$fn($($arg),*) })* } impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for ::std::sync::Arc<::std::sync::RwLock<_T_>> { $(fn $fn (&mut $self $(,$arg:$ty)*) -> $ret { $self.write().unwrap().$fn($($arg),*) })* } }; ); flex_trait_mut!(Handle { fn handle (&mut self, _input: &E) -> Perhaps { Ok(None) } }); pub trait Command: Send + Sync + Sized { fn execute (&self, state: &mut S) -> Perhaps; fn delegate (&self, state: &mut S, wrap: impl Fn(Self)->T) -> Perhaps where Self: Sized { Ok(self.execute(state)?.map(wrap)) } } impl> Command for Option { fn execute (&self, _: &mut S) -> Perhaps { Ok(None) } fn delegate (&self, _: &mut S, _: impl Fn(Self)->U) -> Perhaps where Self: Sized { Ok(None) } } /// Implement [Command] for given `State` and `handler` #[macro_export] macro_rules! command { ($(<$($l:lifetime),+>)?|$self:ident:$Command:ty,$state:ident:$State:ty|$handler:expr) => { impl$(<$($l),+>)? ::tengri::input::Command<$State> for $Command { fn execute (&$self, $state: &mut $State) -> Perhaps { Ok($handler) } } }; } #[macro_export] macro_rules! def_command (($Command:ident: |$state:ident: $State:ty| { $($Variant:ident$({$($arg:ident:$Arg:ty),+ $(,)?})?=>$body:expr),* $(,)? })=>{ #[derive(Debug)] pub enum $Command { $($Variant $({ $($arg: $Arg),* })?),* } impl Command<$State> for $Command { fn execute (&self, $state: &mut $State) -> Perhaps { match self { $(Self::$Variant $({ $($arg),* })? => $body,)* _ => unimplemented!("Command<{}>: {self:?}", stringify!($State)), } } } }); /// Implement [Handle] for given `State` and `handler`. #[macro_export] macro_rules! handle { (|$self:ident:$State:ty,$input:ident|$handler:expr) => { impl ::tengri::input::Handle for $State { fn handle (&mut $self, $input: &E) -> Perhaps { $handler } } }; ($E:ty: |$self:ident:$State:ty,$input:ident|$handler:expr) => { impl ::tengri::input::Handle<$E> for $State { fn handle (&mut $self, $input: &$E) -> Perhaps<<$E as ::tengri::input::Input>::Handled> { $handler } } } }