diff --git a/core/src/core_macros.rs b/core/src/core_macros.rs deleted file mode 100644 index d5ada8f..0000000 --- a/core/src/core_macros.rs +++ /dev/null @@ -1,102 +0,0 @@ -/// Define and reexport submodules. -#[macro_export] macro_rules! modules( - ($($($feat:literal?)? $name:ident),* $(,)?) => { $( - $(#[cfg(feature=$feat)])? mod $name; - $(#[cfg(feature=$feat)])? pub use self::$name::*; - )* }; - ($($($feat:literal?)? $name:ident $body:block),* $(,)?) => { $( - $(#[cfg(feature=$feat)])? mod $name $body - $(#[cfg(feature=$feat)])? pub use self::$name::*; - )* }; -); - -/// Define a trait an implement it for read-only wrapper types. */ -#[macro_export] macro_rules! flex_trait ( - ($Trait:ident $(<$($A:ident:$T:ident),+>)? $(:$dep:ident $(+$dep2:ident)*)? { - $(fn $fn:ident (&$self:ident $(, $arg:ident:$ty:ty)*) -> $ret:ty $body:block)* - }) => { - pub trait $Trait $(<$($A: $T),+>)? $(:$dep$(+$dep2)*)? { - $(fn $fn (&$self $(,$arg:$ty)*) -> $ret $body)* - } - impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for &_T_ { - $(fn $fn (&$self $(,$arg:$ty)*) -> $ret { (*$self).$fn($($arg),*) })* - } - impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for &mut _T_ { - $(fn $fn (&$self $(,$arg:$ty)*) -> $ret { (**$self).$fn($($arg),*) })* - } - impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for ::std::sync::Arc<_T_> { - $(fn $fn (&$self $(,$arg:$ty)*) -> $ret { (*$self).$fn($($arg),*) })* - } - //impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for Option<_T_> { - //$(fn $fn (&$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 (&$self $(,$arg:$ty)*) -> $ret { (*$self).lock().unwrap().$fn($($arg),*) })* - //} - //impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for ::std::sync::RwLock<_T_> { - //$(fn $fn (&$self $(,$arg:$ty)*) -> $ret { $self.read().unwrap().$fn($($arg),*) })* - //} - }); - -/// 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),*) })* - } - }; -); - -/// Implement [`Debug`] in bulk. -#[macro_export] macro_rules! impl_debug(($($S:ty|$self:ident,$w:ident|$body:block)*)=>{ - $(impl std::fmt::Debug for $S { - fn fmt (&$self, $w: &mut std::fmt::Formatter) -> std::fmt::Result $body - })* }); - -/// Implement [`From`] in bulk. -#[macro_export] macro_rules! from( - ($(<$($lt:lifetime),+>)?|$state:ident:$Source:ty|$Target:ty=$cb:expr) => { - impl $(<$($lt),+>)? From<$Source> for $Target { - fn from ($state:$Source) -> Self { $cb }}}; - ($($Struct:ty { $( - $(<$($l:lifetime),* $($T:ident$(:$U:ident)?),*>)? ($source:ident: $From:ty) $expr:expr - );+ $(;)? })*) => { $( - $(impl $(<$($l),* $($T$(:$U)?),*>)? From<$From> for $Struct { - fn from ($source: $From) -> Self { $expr } })+ )* }; ); - -/// Implement [Has]. -#[macro_export] macro_rules! has(($T:ty: |$self:ident : $S:ty| $x:expr) => { - impl Has<$T> for $S { - fn get (&$self) -> &$T { &$x } - fn get_mut (&mut $self) -> &mut $T { &mut $x } } };); - -/// Implement [MaybeHas]. -#[macro_export] macro_rules! maybe_has( - ($T:ty: |$self:ident : $S:ty| $x:block; $y:block $(;)?) => { - impl MaybeHas<$T> for $S { - fn get (&$self) -> Option<&$T> $x - fn get_mut (&mut $self) -> Option<&mut $T> $y } };); diff --git a/core/src/lib.rs b/core/src/lib.rs index 0c63c05..b06b55e 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,13 +1,38 @@ -mod core_macros; pub(crate) use std::error::Error; /// Standard result type. pub type Usually = Result>; /// Standard optional result type. pub type Perhaps = Result, Box>; +/// Implement [`Debug`] in bulk. +#[macro_export] macro_rules! impl_debug(($($S:ty|$self:ident,$w:ident|$body:block)*)=>{ + $(impl std::fmt::Debug for $S { + fn fmt (&$self, $w: &mut std::fmt::Formatter) -> std::fmt::Result $body + })* }); +/// Implement [`From`] in bulk. +#[macro_export] macro_rules! from( + ($(<$($lt:lifetime),+>)?|$state:ident:$Source:ty|$Target:ty=$cb:expr) => { + impl $(<$($lt),+>)? From<$Source> for $Target { + fn from ($state:$Source) -> Self { $cb }}}; + ($($Struct:ty { $( + $(<$($l:lifetime),* $($T:ident$(:$U:ident)?),*>)? ($source:ident: $From:ty) $expr:expr + );+ $(;)? })*) => { $( + $(impl $(<$($l),* $($T$(:$U)?),*>)? From<$From> for $Struct { + fn from ($source: $From) -> Self { $expr } })+ )* }; ); /// Type-dispatched `get` and `get_mut`. pub trait Has: Send + Sync { fn get (&self) -> &T; fn get_mut (&mut self) -> &mut T; } +/// Implement [Has]. +#[macro_export] macro_rules! has(($T:ty: |$self:ident : $S:ty| $x:expr) => { + impl Has<$T> for $S { + fn get (&$self) -> &$T { &$x } + fn get_mut (&mut $self) -> &mut $T { &mut $x } } };); /// Type-dispatched `get` and `get_mut` that return an [Option]-wrapped result. pub trait MaybeHas: Send + Sync { fn get (&self) -> Option<&T>; fn get_mut (&mut self) -> Option<&mut T>; } +/// Implement [MaybeHas]. +#[macro_export] macro_rules! maybe_has( + ($T:ty: |$self:ident : $S:ty| $x:block; $y:block $(;)?) => { + impl MaybeHas<$T> for $S { + fn get (&$self) -> Option<&$T> $x + fn get_mut (&mut $self) -> Option<&mut $T> $y } };); /// May compute a `RetVal` from `Args`. pub trait Eval { /// A custom operation on [Args] that may return [Result::Err] or [Option::None]. diff --git a/dsl/src/dsl.rs b/dsl/src/dsl.rs index 979585d..530e4f5 100644 --- a/dsl/src/dsl.rs +++ b/dsl/src/dsl.rs @@ -1,81 +1,46 @@ //#![feature(adt_const_params)] //#![feature(type_alias_impl_trait)] -#![feature(if_let_guard)] #![feature(impl_trait_in_fn_trait_return)] #![feature(const_precise_live_drops)] extern crate const_panic; use const_panic::PanicFmt; use std::fmt::Debug; - +pub(crate) use ::tengri_core::*; pub(crate) use std::error::Error; -pub(crate) use std::sync::Arc; - pub(crate) use konst::string::{str_range, char_indices}; pub(crate) use thiserror::Error; -pub(crate) use ::tengri_core::*; - pub(crate) use self::DslError::*; -mod dsl_conv; -pub use self::dsl_conv::*; +mod dsl_conv; pub use self::dsl_conv::*; +mod dsl_types; pub use self::dsl_types::*; +#[cfg(test)] mod dsl_test; -mod dsl_parse; -pub(crate) use self::dsl_parse::*; -pub mod parse { pub use crate::dsl_parse::*; } - -#[cfg(test)] -mod dsl_test; - -flex_trait!(Dsl: Debug + Send + Sync + Sized { - fn src (&self) -> &str { - unreachable!("Dsl::src default impl") - } -}); -impl Dsl for Arc { - fn src (&self) -> &str { self.as_ref() } +pub trait Dsl: Debug + Send + Sync + Sized { + fn src (&self) -> &str; } + impl<'s> Dsl for &'s str { + fn src (&self) -> &str { self } +} + +impl Dsl for String { + fn src (&self) -> &str { self.as_str() } +} + +impl Dsl for std::sync::Arc { fn src (&self) -> &str { self.as_ref() } } + impl Dsl for Option { fn src (&self) -> &str { if let Some(dsl) = self { dsl.src() } else { "" } } } -impl DslExp for D {} -pub trait DslExp: Dsl { - fn exp (&self) -> DslPerhaps<&str> { - Ok(exp_peek(self.src())?) - } - fn head (&self) -> DslPerhaps<&str> { - Ok(peek(&self.src()[1..])?) - } - fn tail (&self) -> DslPerhaps<&str> { - Ok(if let Some((head_start, head_len)) = seek(&self.src()[1..])? { - peek(&self.src()[(1+head_start+head_len)..])? - } else { - None - }) - } +impl Dsl for &D { + fn src (&self) -> &str { (*self).src() } } -impl DslSym for D {} -pub trait DslSym: Dsl { - fn sym (&self) -> DslPerhaps<&str> { crate::parse::sym_peek(self.src()) } -} - -impl DslKey for D {} -pub trait DslKey: Dsl { - fn key (&self) -> DslPerhaps<&str> { crate::parse::key_peek(self.src()) } -} - -impl DslText for D {} -pub trait DslText: Dsl { - fn text (&self) -> DslPerhaps<&str> { crate::parse::text_peek(self.src()) } -} - -impl DslNum for D {} -pub trait DslNum: Dsl { - fn num (&self) -> DslPerhaps<&str> { crate::parse::num_peek(self.src()) } +impl Dsl for &mut D { + fn src (&self) -> &str { (**self).src() } } /// DSL-specific result type. diff --git a/dsl/src/dsl_parse.rs b/dsl/src/dsl_types.rs similarity index 56% rename from dsl/src/dsl_parse.rs rename to dsl/src/dsl_types.rs index 25eef20..0a5402d 100644 --- a/dsl/src/dsl_parse.rs +++ b/dsl/src/dsl_types.rs @@ -6,13 +6,13 @@ macro_rules! iter_chars(($source:expr => |$i:ident, $c:ident|$val:expr)=>{ macro_rules! def_peek_seek(($peek:ident, $seek:ident, $seek_start:ident, $seek_length:ident)=>{ /// Find a slice corrensponding to a syntax token. - pub const fn $peek (source: &str) -> DslPerhaps<&str> { + const fn $peek (source: &str) -> DslPerhaps<&str> { match $seek(source) { Ok(Some((start, length))) => Ok(Some(str_range(source, start, start + length))), Ok(None) => Ok(None), Err(e) => Err(e) } } /// Find a start and length corresponding to a syntax token. - pub const fn $seek (source: &str) -> DslPerhaps<(usize, usize)> { + const fn $seek (source: &str) -> DslPerhaps<(usize, usize)> { match $seek_start(source) { Ok(Some(start)) => match $seek_length(str_range(source, start, source.len() - start)) { Ok(Some(length)) => Ok(Some((start, length))), @@ -22,10 +22,31 @@ macro_rules! def_peek_seek(($peek:ident, $seek:ident, $seek_start:ident, $seek_l Ok(None) => Ok(None), Err(e) => Err(e) } } }); +const fn is_whitespace (c: char) -> bool { matches!(c, ' '|'\n'|'\r'|'\t') } + +pub trait DslExp: Dsl { + fn exp (&self) -> DslPerhaps { + todo!(); + Ok(Some(self)) + } + fn exp_head (&self) -> DslPerhaps { + todo!(); + Ok(Some(self)) + } + fn exp_tail (&self) -> DslPerhaps { + todo!(); + Ok(Some(self)) + } + fn exp_next (&mut self) -> DslPerhaps { + todo!(); + Ok(Some(self)) + } +} +impl DslExp for D {} def_peek_seek!(exp_peek, exp_seek, exp_seek_start, exp_seek_length); -pub const fn is_exp_start (c: char) -> bool { matches!(c, '(') } -pub const fn is_exp_end (c: char) -> bool { matches!(c, ')') } -pub const fn exp_seek_start (mut source: &str) -> DslPerhaps { +const fn is_exp_start (c: char) -> bool { matches!(c, '(') } +const fn is_exp_end (c: char) -> bool { matches!(c, ')') } +const fn exp_seek_start (mut source: &str) -> DslPerhaps { iter_chars!(source => |i, c| if is_exp_start(c) { return Ok(Some(i)) } else if !is_whitespace(c) { @@ -33,7 +54,7 @@ pub const fn exp_seek_start (mut source: &str) -> DslPerhaps { }); Ok(None) } -pub const fn exp_seek_length (mut source: &str) -> DslPerhaps { +const fn exp_seek_length (mut source: &str) -> DslPerhaps { let mut depth = 0; iter_chars!(source => |i, c| if is_exp_start(c) { depth += 1; @@ -49,11 +70,13 @@ pub const fn exp_seek_length (mut source: &str) -> DslPerhaps { Ok(None) } +pub trait DslSym: Dsl { fn sym (&self) -> DslPerhaps<&str> { sym_peek(self.src()) } } +impl DslSym for D {} def_peek_seek!(sym_peek, sym_seek, sym_seek_start, sym_seek_length); -pub const fn is_sym_start (c: char) -> bool { matches!(c, ':'|'@') } -pub const fn is_sym_char (c: char) -> bool { matches!(c, 'a'..='z'|'A'..='Z'|'0'..='9'|'-') } -pub const fn is_sym_end (c: char) -> bool { matches!(c, ' '|'\n'|'\r'|'\t'|')') } -pub const fn sym_seek_start (mut source: &str) -> DslPerhaps { +const fn is_sym_start (c: char) -> bool { matches!(c, ':'|'@') } +const fn is_sym_char (c: char) -> bool { matches!(c, 'a'..='z'|'A'..='Z'|'0'..='9'|'-') } +const fn is_sym_end (c: char) -> bool { matches!(c, ' '|'\n'|'\r'|'\t'|')') } +const fn sym_seek_start (mut source: &str) -> DslPerhaps { iter_chars!(source => |i, c| if is_sym_start(c) { return Ok(Some(i)) } else if !is_whitespace(c) { @@ -61,7 +84,7 @@ pub const fn sym_seek_start (mut source: &str) -> DslPerhaps { }); Ok(None) } -pub const fn sym_seek_length (mut source: &str) -> DslPerhaps { +const fn sym_seek_length (mut source: &str) -> DslPerhaps { iter_chars!(source => |i, c| if is_sym_end(c) { return Ok(Some(i)) } else if !is_sym_char(c) { @@ -70,11 +93,13 @@ pub const fn sym_seek_length (mut source: &str) -> DslPerhaps { Ok(None) } +pub trait DslKey: Dsl { fn key (&self) -> DslPerhaps<&str> { key_peek(self.src()) } } +impl DslKey for D {} def_peek_seek!(key_peek, key_seek, key_seek_start, key_seek_length); -pub const fn is_key_start (c: char) -> bool { matches!(c, '/'|'a'..='z') } -pub const fn is_key_char (c: char) -> bool { matches!(c, 'a'..='z'|'0'..='9'|'-'|'/') } -pub const fn is_key_end (c: char) -> bool { matches!(c, ' '|'\n'|'\r'|'\t'|')') } -pub const fn key_seek_start (mut source: &str) -> DslPerhaps { +const fn is_key_start (c: char) -> bool { matches!(c, '/'|'a'..='z') } +const fn is_key_char (c: char) -> bool { matches!(c, 'a'..='z'|'0'..='9'|'-'|'/') } +const fn is_key_end (c: char) -> bool { matches!(c, ' '|'\n'|'\r'|'\t'|')') } +const fn key_seek_start (mut source: &str) -> DslPerhaps { iter_chars!(source => |i, c| if is_key_start(c) { return Ok(Some(i)) } else if !is_whitespace(c) { @@ -82,7 +107,7 @@ pub const fn key_seek_start (mut source: &str) -> DslPerhaps { }); Ok(None) } -pub const fn key_seek_length (mut source: &str) -> DslPerhaps { +const fn key_seek_length (mut source: &str) -> DslPerhaps { iter_chars!(source => |i, c| if is_key_end(c) { return Ok(Some(i)) } else if !is_key_char(c) { @@ -91,10 +116,12 @@ pub const fn key_seek_length (mut source: &str) -> DslPerhaps { Ok(None) } +pub trait DslText: Dsl { fn text (&self) -> DslPerhaps<&str> { text_peek(self.src()) } } +impl DslText for D {} def_peek_seek!(text_peek, text_seek, text_seek_start, text_seek_length); -pub const fn is_text_start (c: char) -> bool { matches!(c, '"') } -pub const fn is_text_end (c: char) -> bool { matches!(c, '"') } -pub const fn text_seek_start (mut source: &str) -> DslPerhaps { +const fn is_text_start (c: char) -> bool { matches!(c, '"') } +const fn is_text_end (c: char) -> bool { matches!(c, '"') } +const fn text_seek_start (mut source: &str) -> DslPerhaps { iter_chars!(source => |i, c| if is_text_start(c) { return Ok(Some(i)) } else if !is_whitespace(c) { @@ -102,13 +129,15 @@ pub const fn text_seek_start (mut source: &str) -> DslPerhaps { }); Ok(None) } -pub const fn text_seek_length (mut source: &str) -> DslPerhaps { +const fn text_seek_length (mut source: &str) -> DslPerhaps { iter_chars!(source => |i, c| if is_text_end(c) { return Ok(Some(i)) }); Ok(None) } +pub trait DslNum: Dsl { fn num (&self) -> DslPerhaps<&str> { num_peek(self.src()) } } +impl DslNum for D {} def_peek_seek!(num_peek, num_seek, num_seek_start, num_seek_length); -pub const fn num_seek_start (mut source: &str) -> DslPerhaps { +const fn num_seek_start (mut source: &str) -> DslPerhaps { iter_chars!(source => |i, c| if is_digit(c) { return Ok(Some(i)); } else if !is_whitespace(c) { @@ -116,7 +145,7 @@ pub const fn num_seek_start (mut source: &str) -> DslPerhaps { }); Ok(None) } -pub const fn num_seek_length (mut source: &str) -> DslPerhaps { +const fn num_seek_length (mut source: &str) -> DslPerhaps { iter_chars!(source => |i, c| if is_num_end(c) { return Ok(Some(i)) } else if !is_digit(c) { @@ -124,8 +153,8 @@ pub const fn num_seek_length (mut source: &str) -> DslPerhaps { }); Ok(None) } -pub const fn is_digit (c: char) -> bool { matches!(c, '0'..='9') } -pub const fn is_num_end (c: char) -> bool { matches!(c, ' '|'\n'|'\r'|'\t'|')') } +const fn is_digit (c: char) -> bool { matches!(c, '0'..='9') } +const fn is_num_end (c: char) -> bool { matches!(c, ' '|'\n'|'\r'|'\t'|')') } pub const fn to_number (digits: &str) -> Result { let mut iter = char_indices(digits); let mut value = 0; @@ -145,39 +174,3 @@ pub const fn to_digit (c: char) -> Result { _ => return Err(Unexpected(c)) }) } - -pub const fn peek (mut src: &str) -> DslPerhaps<&str> { - Ok(Some(match () { - _ if let Ok(Some(exp)) = exp_peek(src) => exp, - _ if let Ok(Some(sym)) = sym_peek(src) => sym, - _ if let Ok(Some(key)) = key_peek(src) => key, - _ if let Ok(Some(num)) = num_peek(src) => num, - _ if let Ok(Some(text)) = text_peek(src) => text, - _ => { - iter_chars!(src => |_i, c| if !is_whitespace(c) { - return Err(Unexpected(c)) - }); - return Ok(None) - } - })) -} - -pub const fn seek (mut src: &str) -> DslPerhaps<(usize, usize)> { - Ok(Some(match () { - _ if let Ok(Some(exp)) = exp_seek(src) => exp, - _ if let Ok(Some(sym)) = sym_seek(src) => sym, - _ if let Ok(Some(key)) = key_seek(src) => key, - _ if let Ok(Some(num)) = num_seek(src) => num, - _ if let Ok(Some(text)) = text_seek(src) => text, - _ => { - iter_chars!(src => |_i, c| if !is_whitespace(c) { - return Err(Unexpected(c)) - }); - return Ok(None) - } - })) -} - -pub const fn is_whitespace (c: char) -> bool { - matches!(c, ' '|'\n'|'\r'|'\t') -} diff --git a/input/src/input.rs b/input/src/input_command.rs similarity index 50% rename from input/src/input.rs rename to input/src/input_command.rs index 7b451ee..6051277 100644 --- a/input/src/input.rs +++ b/input/src/input_command.rs @@ -1,25 +1,5 @@ use crate::*; -/// 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); -} - -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 diff --git a/input/src/input_dsl.rs b/input/src/input_dsl.rs index bb3c353..0bec9a8 100644 --- a/input/src/input_dsl.rs +++ b/input/src/input_dsl.rs @@ -1,10 +1,8 @@ use crate::*; - /// Map of each event (e.g. key combination) to /// all command expressions bound to it by /// all loaded input layers. type EventMapImpl = BTreeMap>>; - /// A collection of input bindings. /// /// Each contained layer defines a mapping from input event to command invocation @@ -16,27 +14,8 @@ type EventMapImpl = BTreeMap>>; /// that .event()binding's value is returned. #[derive(Debug)] pub struct EventMap(EventMapImpl); - -/// An input binding. -#[derive(Debug, Clone)] -pub struct Binding { - pub command: C, - pub condition: Option, - pub description: Option>, - pub source: Option>, -} - -/// Input bindings are only returned if this evaluates to true -#[derive(Clone)] -pub struct Condition(Arcbool + Send + Sync>>); - -impl_debug!(Condition |self, w| { write!(w, "*") }); - /// Default is always empty map regardless if `E` and `C` implement [Default]. -impl Default for EventMap { - fn default () -> Self { Self(Default::default()) } -} - +impl Default for EventMap { fn default () -> Self { Self(Default::default()) } } impl EventMap { /// Create a new event map pub fn new () -> Self { @@ -49,7 +28,7 @@ impl EventMap { } /// Add a binding to an event map. pub fn add (&mut self, event: E, binding: Binding) -> &mut Self { - if !self.0.contains_key(&event) { + if (!self.0.contains_key(&event)) { self.0.insert(event.clone(), Default::default()); } self.0.get_mut(&event).unwrap().push(binding); @@ -75,49 +54,33 @@ impl EventMap { } /// Create event map from string. pub fn from_source (source: impl AsRef) -> Usually where E: From> { - Self::from_dsl(&mut source.as_ref()) + Self::from_dsl(source.as_ref()) } /// Create event map from DSL tokenizer. - pub fn from_dsl <'s, > (dsl: &'s mut impl Dsl) -> Usually where E: From> { + pub fn from_dsl (mut dsl: impl Dsl) -> Usually where E: From> { let mut map: Self = Default::default(); - if let Some(dsl) = dsl.exp()? { - let mut head = dsl.head()?; - let mut tail = dsl.tail()?; - loop { - if let Some(ref token) = head { - if let Some(ref text) = token.text()? { - map.0.extend(Self::from_path(PathBuf::from(text))?.0); - continue - } - //if let Some(ref exp) = token.exp()? { - ////_ if let Some(sym) = token.head()?.sym()?.as_ref() => { - ////todo!() - ////}, - ////_ if Some(&"if") == token.head()?.key()?.as_ref() => { - ////todo!() - ////}, - //return Err(format!("unexpected: {:?}", token.exp()).into()) - //} - return Err(format!("unexpected: {token:?}").into()) - } else { - break - } - if let Some(next) = tail { - head = next.head()?; - tail = next.tail()?; - } else { - break - } + while let Some(dsl) = dsl.exp_next()? { + if let Some(path) = dsl.text()? { + map.0.extend(Self::from_path(PathBuf::from(path.as_ref() as &str))?.0) + } else if dsl.exp_head()?.key()? == Some("if") { + todo!() + //map.add(sym.into(), Binding::from_dsl(dsl.exp_tail())?); + } else if let Some(sym) = dsl.exp_head()?.sym()? { + todo!() + //map.add(sym.into(), Binding::from_dsl(dsl.exp_tail())?); } - } else if let Some(text) = dsl.text()? { - todo!("load from file path") - } else { - todo!("return error for invalid input") } Ok(map) } } - +/// An input binding. +#[derive(Debug)] +pub struct Binding { + pub command: C, + pub condition: Option, + pub description: Option>, + pub source: Option>, +} impl Binding { fn from_dsl (dsl: impl Dsl) -> Usually { let mut command: Option = None; @@ -131,6 +94,8 @@ impl Binding { } } } +pub struct Condition(Boxbool + Send + Sync>); +impl_debug!(Condition |self, w| { write!(w, "*") }); fn unquote (x: &str) -> &str { let mut chars = x.chars(); diff --git a/input/src/input_handle.rs b/input/src/input_handle.rs new file mode 100644 index 0000000..2be276c --- /dev/null +++ b/input/src/input_handle.rs @@ -0,0 +1,77 @@ +use crate::*; +use std::sync::{Mutex, Arc, RwLock}; + +/// 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); +} + +/// Implement the [Handle] trait. +#[macro_export] macro_rules! handle { + (|$self:ident:$Struct:ty,$input:ident|$handler:expr) => { + impl ::tengri::input::Handle for $Struct { + fn handle (&mut $self, $input: &E) -> Perhaps { + $handler + } + } + }; + ($E:ty: |$self:ident:$Struct:ty,$input:ident|$handler:expr) => { + impl ::tengri::input::Handle<$E> for $Struct { + fn handle (&mut $self, $input: &$E) -> + Perhaps<<$E as ::tengri::input::Input>::Handled> + { + $handler + } + } + } +} + +/// Handle input +pub trait Handle { + fn handle (&mut self, _input: &E) -> Perhaps { + Ok(None) + } +} +impl> Handle for &mut H { + fn handle (&mut self, context: &E) -> Perhaps { + (*self).handle(context) + } +} +impl> Handle for Option { + fn handle (&mut self, context: &E) -> Perhaps { + if let Some(handle) = self { + handle.handle(context) + } else { + Ok(None) + } + } +} +impl Handle for Mutex where H: Handle { + fn handle (&mut self, context: &E) -> Perhaps { + self.get_mut().unwrap().handle(context) + } +} +impl Handle for Arc> where H: Handle { + fn handle (&mut self, context: &E) -> Perhaps { + self.lock().unwrap().handle(context) + } +} +impl Handle for RwLock where H: Handle { + fn handle (&mut self, context: &E) -> Perhaps { + self.write().unwrap().handle(context) + } +} +impl Handle for Arc> where H: Handle { + fn handle (&mut self, context: &E) -> Perhaps { + self.write().unwrap().handle(context) + } +} diff --git a/input/src/input_macros.rs b/input/src/input_macros.rs index e47b902..ae5758c 100644 --- a/input/src/input_macros.rs +++ b/input/src/input_macros.rs @@ -1,30 +1,10 @@ -/// Implement [Command] for given `State` and `handler` +/** 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 { + impl$(<$($l),+>)? Command<$State> for $Command { fn execute ($self, $state: &mut $State) -> Perhaps { Ok($handler) } } }; } - -/// 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 - } - } - } -} diff --git a/input/src/input_test.rs b/input/src/input_test.rs deleted file mode 100644 index 8373435..0000000 --- a/input/src/input_test.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::*; - -#[test] fn test_stub_input () -> Usually<()> { - use crate::*; - struct TestInput(bool); - enum TestEvent { Test1 } - impl Input for TestInput { - type Event = TestEvent; - type Handled = (); - fn event (&self) -> &Self::Event { - &TestEvent::Test1 - } - fn is_done (&self) -> bool { - self.0 - } - fn done (&self) {} - } - let _ = TestInput(true).event(); - assert!(TestInput(true).is_done()); - assert!(!TestInput(false).is_done()); - Ok(()) -} - -#[cfg(all(test, feature = "dsl"))] #[test] fn test_dsl_keymap () -> Usually<()> { - let _keymap = CstIter::new(""); - Ok(()) -} - diff --git a/input/src/lib.rs b/input/src/lib.rs index f219c64..0779092 100644 --- a/input/src/lib.rs +++ b/input/src/lib.rs @@ -3,14 +3,41 @@ pub(crate) use std::fmt::Debug; pub(crate) use std::sync::Arc; -pub(crate) use std::collections::BTreeMap; +pub(crate) use std::collections::{BTreeMap, HashMap}; pub(crate) use std::path::{Path, PathBuf}; pub(crate) use std::fs::exists; pub(crate) use tengri_core::*; mod input_macros; -mod input; pub use self::input::*; +mod input_command; pub use self::input_command::*; +mod input_handle; pub use self::input_handle::*; + #[cfg(feature = "dsl")] pub(crate) use ::tengri_dsl::*; #[cfg(feature = "dsl")] mod input_dsl; #[cfg(feature = "dsl")] pub use self::input_dsl::*; -#[cfg(test)] mod input_test; + +#[cfg(test)] #[test] fn test_stub_input () -> Usually<()> { + use crate::*; + struct TestInput(bool); + enum TestEvent { Test1 } + impl Input for TestInput { + type Event = TestEvent; + type Handled = (); + fn event (&self) -> &Self::Event { + &TestEvent::Test1 + } + fn is_done (&self) -> bool { + self.0 + } + fn done (&self) {} + } + let _ = TestInput(true).event(); + assert!(TestInput(true).is_done()); + assert!(!TestInput(false).is_done()); + Ok(()) +} + +#[cfg(all(test, feature = "dsl"))] #[test] fn test_dsl_keymap () -> Usually<()> { + let _keymap = CstIter::new(""); + Ok(()) +} diff --git a/output/src/ops.rs b/output/src/ops.rs index bdbcff0..846c86c 100644 --- a/output/src/ops.rs +++ b/output/src/ops.rs @@ -373,7 +373,7 @@ transform_xy_unit!("padding/x" "padding/y" "padding/xy"|self: Padding, area|{ /// the layout elements that are provided by this crate. #[cfg(feature = "dsl")] mod ops_dsl { use crate::*; - //use ::tengri_dsl::*; + use ::tengri_dsl::*; //macro_rules! dsl { //($( diff --git a/proc/src/proc_flex.rs b/proc/src/proc_flex.rs deleted file mode 100644 index 039dd7d..0000000 --- a/proc/src/proc_flex.rs +++ /dev/null @@ -1,2 +0,0 @@ -// TODO: #[derive(Flex, FlexMut, FlexOption, FlexResult ... ?)] -// better derive + annotations diff --git a/proc/src/proc_view.rs b/proc/src/proc_view.rs index 13a5d5c..bd44c96 100644 --- a/proc/src/proc_view.rs +++ b/proc/src/proc_view.rs @@ -56,13 +56,13 @@ impl ViewDef { let builtins = builtins_with_boxes_output(quote! { #output }) .map(|(builtin, builtin_ty)|match builtin { Single(name) => quote! { - if dsl.head()?.key()? == Some(#name) { + if dsl.exp_head()?.key()? == Some(#name) { return Ok(Some(#builtin_ty::from_dsl_or_else(self, dsl, ||format!("failed to load builtin").into())?.boxed())) } }, Prefix(name) => quote! { - if let Some(key) = dsl.head()?.key()? && key.starts_with(#name) { + if let Some(key) = dsl.exp_head()?.key()? && key.starts_with(#name) { return Ok(Some(#builtin_ty::from_dsl_or_else(self, dsl, ||format!("failed to load builtin").into())?.boxed())) }