From 3df1938626d58ffcfddc90be4ad067304102be31 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 3 May 2025 02:13:22 +0300 Subject: [PATCH 1/2] dsl: InputLayerCond; collect macros --- dsl/src/dsl_context.rs | 98 ------------------------------------------ dsl/src/dsl_iter.rs | 6 +++ dsl/src/dsl_macros.rs | 85 ++++++++++++++++++++++++++++++++++++ dsl/src/lib.rs | 14 ++++++ input/src/input_dsl.rs | 22 ++++++---- output/src/view.rs | 6 +-- 6 files changed, 121 insertions(+), 110 deletions(-) diff --git a/dsl/src/dsl_context.rs b/dsl/src/dsl_context.rs index 34f9dcd..b6daf5f 100644 --- a/dsl/src/dsl_context.rs +++ b/dsl/src/dsl_context.rs @@ -41,101 +41,3 @@ impl, U> Context for Option { self.as_ref().map(|s|s.get_or_fail(dsl)).expect("no provider") } } - -/// Implement `Context` for a context and type. -#[macro_export] macro_rules! provide { - // Provide a value to the EDN template - ($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { - impl Context<$type> for $State { - #[allow(unreachable_code)] - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { $(Sym($pat) => $expr,)* _ => return None }) - } - } - }; - // Provide a value more generically - ($lt:lifetime: $type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { - impl<$lt> Context<$lt, $type> for $State { - #[allow(unreachable_code)] - fn get (&$lt $self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { $(Sym($pat) => $expr,)* _ => return None }) - } - } - }; -} - -/// Implement `Context` for a context and numeric type. -/// -/// This enables support for numeric literals. -#[macro_export] macro_rules! provide_num { - // Provide a value that may also be a numeric literal in the EDN, to a generic implementation. - ($type:ty:|$self:ident:<$T:ident:$Trait:path>|{ $($pat:pat => $expr:expr),* $(,)? }) => { - impl<$T: $Trait> Context<$type> for $T { - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { $(Sym($pat) => $expr,)* Num(n) => *n as $type, _ => return None }) - } - } - }; - // Provide a value that may also be a numeric literal in the EDN, to a concrete implementation. - ($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { - impl Context<$type> for $State { - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { $(Sym($pat) => $expr,)* Num(n) => *n as $type, _ => return None }) - } - } - }; -} - -/// Implement `Context` for a context and the boolean type. -/// -/// This enables support for boolean literals. -#[macro_export] macro_rules! provide_bool { - // Provide a value that may also be a numeric literal in the EDN, to a generic implementation. - ($type:ty:|$self:ident:<$T:ident:$Trait:path>|{ $($pat:pat => $expr:expr),* $(,)? }) => { - impl<$T: $Trait> Context<$type> for $T { - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { - Num(n) => match *n { 0 => false, _ => true }, - Sym(":false") | Sym(":f") => false, - Sym(":true") | Sym(":t") => true, - $(Sym($pat) => $expr,)* - _ => return Context::get(self, dsl) - }) - } - } - }; - // Provide a value that may also be a numeric literal in the EDN, to a concrete implementation. - ($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { - impl Context<$type> for $State { - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { - Num(n) => match *n { 0 => false, _ => true }, - Sym(":false") | Sym(":f") => false, - Sym(":true") | Sym(":t") => true, - $(Sym($pat) => $expr,)* - _ => return None - }) - } - } - }; -} - -#[cfg(test)] #[test] fn test_edn_context () { - struct Test; - provide_bool!(bool: |self: Test|{ - ":provide-bool" => true - }); - let test = Test; - assert_eq!(test.get(&Value::Sym(":false")), Some(false)); - assert_eq!(test.get(&Value::Sym(":true")), Some(true)); - assert_eq!(test.get(&Value::Sym(":provide-bool")), Some(true)); - assert_eq!(test.get(&Value::Sym(":missing-bool")), None); - assert_eq!(test.get(&Value::Num(0)), Some(false)); - assert_eq!(test.get(&Value::Num(1)), Some(true)); -} diff --git a/dsl/src/dsl_iter.rs b/dsl/src/dsl_iter.rs index bc69f04..269bc55 100644 --- a/dsl/src/dsl_iter.rs +++ b/dsl/src/dsl_iter.rs @@ -34,6 +34,12 @@ impl<'a> Iterator for TokenIter<'a> { } } +impl<'a> From<&'a str> for TokenIter<'a> { + fn from (source: &'a str) -> Self{ + Self(SourceIter(source)) + } +} + impl<'a> From> for TokenIter<'a> { fn from (source: SourceIter<'a>) -> Self{ Self(source) diff --git a/dsl/src/dsl_macros.rs b/dsl/src/dsl_macros.rs index b39a3ff..338583f 100644 --- a/dsl/src/dsl_macros.rs +++ b/dsl/src/dsl_macros.rs @@ -24,6 +24,7 @@ } } +/// Implement `Context` for one or more base structs, types, and keys. */ #[macro_export] macro_rules! expose { ($([$self:ident:$State:ty] $(([$($Type:tt)*] $(($pat:literal $expr:expr))*))*)*) => { $(expose!(@impl [$self: $State] { $([$($Type)*] => { $($pat => $expr),* })* });)* @@ -51,6 +52,90 @@ }; } +/// Implement `Context` for a context and type. +#[macro_export] macro_rules! provide { + // Provide a value to the EDN template + ($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { + impl Context<$type> for $State { + #[allow(unreachable_code)] + fn get (&$self, dsl: &Value) -> Option<$type> { + use Value::*; + Some(match dsl { $(Sym($pat) => $expr,)* _ => return None }) + } + } + }; + // Provide a value more generically + ($lt:lifetime: $type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { + impl<$lt> Context<$lt, $type> for $State { + #[allow(unreachable_code)] + fn get (&$lt $self, dsl: &Value) -> Option<$type> { + use Value::*; + Some(match dsl { $(Sym($pat) => $expr,)* _ => return None }) + } + } + }; +} + +/// Implement `Context` for a context and numeric type. +/// +/// This enables support for numeric literals. +#[macro_export] macro_rules! provide_num { + // Provide a value that may also be a numeric literal in the EDN, to a generic implementation. + ($type:ty:|$self:ident:<$T:ident:$Trait:path>|{ $($pat:pat => $expr:expr),* $(,)? }) => { + impl<$T: $Trait> Context<$type> for $T { + fn get (&$self, dsl: &Value) -> Option<$type> { + use Value::*; + Some(match dsl { $(Sym($pat) => $expr,)* Num(n) => *n as $type, _ => return None }) + } + } + }; + // Provide a value that may also be a numeric literal in the EDN, to a concrete implementation. + ($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { + impl Context<$type> for $State { + fn get (&$self, dsl: &Value) -> Option<$type> { + use Value::*; + Some(match dsl { $(Sym($pat) => $expr,)* Num(n) => *n as $type, _ => return None }) + } + } + }; +} + +/// Implement `Context` for a context and the boolean type. +/// +/// This enables support for boolean literals. +#[macro_export] macro_rules! provide_bool { + // Provide a value that may also be a numeric literal in the EDN, to a generic implementation. + ($type:ty:|$self:ident:<$T:ident:$Trait:path>|{ $($pat:pat => $expr:expr),* $(,)? }) => { + impl<$T: $Trait> Context<$type> for $T { + fn get (&$self, dsl: &Value) -> Option<$type> { + use Value::*; + Some(match dsl { + Num(n) => match *n { 0 => false, _ => true }, + Sym(":false") | Sym(":f") => false, + Sym(":true") | Sym(":t") => true, + $(Sym($pat) => $expr,)* + _ => return Context::get(self, dsl) + }) + } + } + }; + // Provide a value that may also be a numeric literal in the EDN, to a concrete implementation. + ($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { + impl Context<$type> for $State { + fn get (&$self, dsl: &Value) -> Option<$type> { + use Value::*; + Some(match dsl { + Num(n) => match *n { 0 => false, _ => true }, + Sym(":false") | Sym(":f") => false, + Sym(":true") | Sym(":t") => true, + $(Sym($pat) => $expr,)* + _ => return None + }) + } + } + }; +} + #[macro_export] macro_rules! impose { ([$self:ident:$Struct:ty] $(($Command:ty : $(($cmd:literal $args:tt $result:expr))*))*) => { $(atom_command!($Command: |$self: $Struct| { $(($cmd $args $result))* });)* diff --git a/dsl/src/lib.rs b/dsl/src/lib.rs index ea0e477..994fc80 100644 --- a/dsl/src/lib.rs +++ b/dsl/src/lib.rs @@ -114,6 +114,20 @@ mod dsl_macros; Ok(()) } +#[cfg(test)] #[test] fn test_dsl_context () { + struct Test; + provide_bool!(bool: |self: Test|{ + ":provide-bool" => true + }); + let test = Test; + assert_eq!(test.get(&Value::Sym(":false")), Some(false)); + assert_eq!(test.get(&Value::Sym(":true")), Some(true)); + assert_eq!(test.get(&Value::Sym(":provide-bool")), Some(true)); + assert_eq!(test.get(&Value::Sym(":missing-bool")), None); + assert_eq!(test.get(&Value::Num(0)), Some(false)); + assert_eq!(test.get(&Value::Num(1)), Some(true)); +} + //#[cfg(test)] #[test] fn test_examples () -> Result<(), ParseError> { //// Let's pretend to render some view. //let source = include_str!("../../tek/src/view_arranger.edn"); diff --git a/input/src/input_dsl.rs b/input/src/input_dsl.rs index 1fe3acf..49f77fc 100644 --- a/input/src/input_dsl.rs +++ b/input/src/input_dsl.rs @@ -70,14 +70,18 @@ impl<'a, S, C: DslCommand<'a, S>, I: DslInput> KeyMap<'a, S, C, I> for TokenIter } } +pub type InputLayerCond<'a, S> = Boxbool + Send + Sync + 'a>; + /// A collection of pre-configured mappings of input events to commands, /// which may be made available subject to given conditions. -pub struct InputMap<'a, S, C: DslCommand<'a, S>, I: DslInput, M: KeyMap<'a, S, C, I> + Send + Sync> { +pub struct InputMap<'a, S, C, I, M> +where + C: DslCommand<'a, S>, + I: DslInput, + M: KeyMap<'a, S, C, I> + Send + Sync +{ __: &'a PhantomData<(S, C, I)>, - pub layers: Vec<( - fn(&S)->bool, - M - )>, + pub layers: Vec<(InputLayerCond<'a, S>, M)>, } impl<'a, S, C, I, M> Default for InputMap<'a, S, C, I, M> @@ -108,15 +112,15 @@ where self } pub fn add_layer (&mut self, keymap: M) -> &mut Self { - self.add_layer_if(|_|true, keymap); + self.add_layer_if(Box::new(|_|true), keymap); self } - pub fn layer_if (mut self, condition: fn(&S)->bool, keymap: M) -> Self { + pub fn layer_if (mut self, condition: InputLayerCond<'a, S>, keymap: M) -> Self { self.add_layer_if(condition, keymap); self } - pub fn add_layer_if (&mut self, condition: fn(&S)->bool, keymap: M) -> &mut Self { - self.layers.push((condition, keymap)); + pub fn add_layer_if (&mut self, condition: InputLayerCond<'a, S>, keymap: M) -> &mut Self { + self.layers.push((Box::new(condition), keymap)); self } } diff --git a/output/src/view.rs b/output/src/view.rs index 28e15bb..c18713f 100644 --- a/output/src/view.rs +++ b/output/src/view.rs @@ -27,14 +27,14 @@ use crate::*; #[cfg(feature = "dsl")] pub struct View<'a, T>( pub &'a T, - pub SourceIter<'a> + pub TokenIter<'a> ); #[cfg(feature = "dsl")] impl<'a, O: Output + 'a, T: ViewContext<'a, O>> Content for View<'a, T> { fn content (&self) -> impl Render { - let iter = self.1.clone(); - while let Some((Token { value, .. }, _)) = iter.next() { + let mut iter = self.1.clone(); + while let Some(Token { value, .. }) = iter.next() { if let Some(content) = self.0.get_content(&value) { return Some(content) } From 21f7f6b38afc966b7b45af442935d48c8c5067d3 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sat, 3 May 2025 02:14:03 +0300 Subject: [PATCH 2/2] 0.13.0: release --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d5c8ab..96211a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -304,9 +304,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ "allocator-api2", "equivalent", @@ -791,9 +791,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags", "errno", @@ -928,13 +928,13 @@ dependencies = [ "fastrand", "getrandom 0.3.2", "once_cell", - "rustix 1.0.5", + "rustix 1.0.7", "windows-sys 0.59.0", ] [[package]] name = "tengri" -version = "0.12.0" +version = "0.13.0" dependencies = [ "tengri_dsl", "tengri_input", @@ -944,7 +944,7 @@ dependencies = [ [[package]] name = "tengri_dsl" -version = "0.12.0" +version = "0.13.0" dependencies = [ "itertools 0.14.0", "konst", @@ -955,7 +955,7 @@ dependencies = [ [[package]] name = "tengri_input" -version = "0.12.0" +version = "0.13.0" dependencies = [ "tengri_dsl", "tengri_tui", @@ -963,7 +963,7 @@ dependencies = [ [[package]] name = "tengri_output" -version = "0.12.0" +version = "0.13.0" dependencies = [ "proptest", "proptest-derive", @@ -974,7 +974,7 @@ dependencies = [ [[package]] name = "tengri_tui" -version = "0.12.0" +version = "0.13.0" dependencies = [ "atomic_float", "better-panic", diff --git a/Cargo.toml b/Cargo.toml index 71ce20f..daeb8ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace.package] -version = "0.12.0" +version = "0.13.0" [workspace] resolver = "2"