From 455d6d00d5f91e7f9f6b9d3711aa47e09900ad46 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Tue, 20 May 2025 22:02:51 +0300 Subject: [PATCH] read explicit lifetime to FromDsl --- dsl/src/dsl_provide.rs | 47 +++++---- input/src/input_dsl.rs | 64 ++++++++---- input/src/input_handle.rs | 4 +- output/src/ops/align.rs | 60 +++++------ output/src/ops/bsp.rs | 62 ++++++------ output/src/ops/cond.rs | 8 +- output/src/ops/thunk.rs | 47 ++++----- output/src/ops/transform.rs | 12 +-- output/src/output.rs | 26 ++--- proc/src/proc_command.rs | 17 ++-- proc/src/proc_expose.rs | 16 +-- proc/src/proc_view.rs | 170 ++++++++++---------------------- tui/src/tui_engine.rs | 3 +- tui/src/tui_engine/tui_input.rs | 2 +- 14 files changed, 252 insertions(+), 286 deletions(-) diff --git a/dsl/src/dsl_provide.rs b/dsl/src/dsl_provide.rs index 92aae3d..d9896de 100644 --- a/dsl/src/dsl_provide.rs +++ b/dsl/src/dsl_provide.rs @@ -18,10 +18,10 @@ pub trait Dsl: Sized { } } } -pub trait FromDsl: Sized { - fn take_from <'state, 'source: 'state> (state: &'state State, token: &mut TokenIter<'source>) +pub trait FromDsl<'source, State>: Sized { + fn take_from <'state> (state: &'state State, token: &mut TokenIter<'source>) -> Perhaps; - fn take_from_or_fail <'state, 'source: 'state> ( + fn take_from_or_fail <'state> ( state: &'state State, token: &mut TokenIter<'source>, error: impl Into> @@ -33,13 +33,6 @@ pub trait FromDsl: Sized { } } } -impl, State> Dsl for State { - fn take <'state, 'source: 'state> (&'state self, token: &mut TokenIter<'source>) - -> Perhaps - { - FromDsl::take_from(self, token) - } -} //impl, T> FromDsl for T { //fn take_from <'state, 'source: 'state> (state: &'state State, token: &mut TokenIter<'source>) //-> Perhaps @@ -51,16 +44,36 @@ impl, State> Dsl for State { /// Implement the [Dsl] trait, which boils down to /// specifying two types and providing an expression. #[macro_export] macro_rules! from_dsl { - ($T:ty: |$state:ident:$S:ty, $words:ident|$expr:expr) => { - impl ::tengri::dsl::FromDsl<$S> for $T { - fn take_from <'state, 'source: 'state> ( - $state: &'state $S, - $words: &mut ::tengri::dsl::TokenIter<'source>, - ) -> ::tengri::Perhaps<$T> { + (@a: $T:ty: |$state:ident, $words:ident|$expr:expr) => { + impl<'source, State: Dsl, A> FromDsl<'source, State> for $T { + fn take_from <'state> ( + $state: &'state State, + $words: &mut TokenIter<'source>, + ) -> Perhaps<$T> { $expr } } - } + }; + (@ab: $T:ty: |$state:ident, $words:ident|$expr:expr) => { + impl<'source, State: Dsl + Dsl, A, B> FromDsl<'source, State> for $T { + fn take_from <'state> ( + $state: &'state State, + $words: &mut TokenIter<'source>, + ) -> Perhaps<$T> { + $expr + } + } + }; + ($T:ty: |$state:ident:$S:ty, $words:ident|$expr:expr) => { + impl<'source> FromDsl<'source, $S> for $T { + fn take_from <'state> ( + $state: &'state $S, + $words: &mut TokenIter<'source>, + ) -> Perhaps<$T> { + $expr + } + } + }; } ///// Maps a sequencer of EDN tokens to parameters of supported types diff --git a/input/src/input_dsl.rs b/input/src/input_dsl.rs index 3c4e8a6..2856c89 100644 --- a/input/src/input_dsl.rs +++ b/input/src/input_dsl.rs @@ -5,13 +5,15 @@ use std::marker::PhantomData; pub trait DslInput: Input { fn matches_dsl (&self, token: &str) -> bool; } /// A pre-configured mapping of input events to commands. -pub trait KeyMap, C: Command, I: DslInput> { +pub trait KeyMap<'source, S, C: FromDsl<'source, S> + Command, I: DslInput> { /// Try to find a command that matches the current input event. fn keybind_resolve (&self, state: &S, input: &I) -> Perhaps; } /// A [SourceIter] can be a [KeyMap]. -impl<'source, S: Dsl, C: Command, I: DslInput> KeyMap for SourceIter<'source> { +impl<'source, S, C: FromDsl<'source, S> + Command, I: DslInput> +KeyMap<'source, S, C, I> +for SourceIter<'source> { fn keybind_resolve (&self, state: &S, input: &I) -> Perhaps { let mut iter = self.clone(); while let Some((token, rest)) = iter.next() { @@ -22,7 +24,7 @@ impl<'source, S: Dsl, C: Command, I: DslInput> KeyMap for SourceI match exp_iter.next() { Some(Token { value: Value::Sym(binding), .. }) => { if input.matches_dsl(binding) { - if let Some(command) = state.take(&mut exp_iter)? { + if let Some(command) = FromDsl::take_from(state, &mut exp_iter)? { return Ok(Some(command)) } } @@ -38,7 +40,9 @@ impl<'source, S: Dsl, C: Command, I: DslInput> KeyMap for SourceI } /// A [TokenIter] can be a [KeyMap]. -impl<'source, S: Dsl, C: Command, I: DslInput> KeyMap for TokenIter<'source> { +impl<'source, S, C: FromDsl<'source, S> + Command, I: DslInput> +KeyMap<'source, S, C, I> +for TokenIter<'source> { fn keybind_resolve (&self, state: &S, input: &I) -> Perhaps { let mut iter = self.clone(); while let Some(next) = iter.next() { @@ -48,7 +52,7 @@ impl<'source, S: Dsl, C: Command, I: DslInput> KeyMap for TokenIt match e.next() { Some(Token { value: Value::Sym(binding), .. }) => { if input.matches_dsl(binding) { - if let Some(command) = state.take(&mut e)? { + if let Some(command) = FromDsl::take_from(state, &mut e)? { return Ok(Some(command)) } } @@ -63,25 +67,37 @@ impl<'source, S: Dsl, C: Command, I: DslInput> KeyMap for TokenIt } } -pub type InputLayerCond = BoxUsually + Send + Sync>; +pub type InputLayerCond<'source, S> = BoxUsually + 'source>; /// A collection of pre-configured mappings of input events to commands, /// which may be made available subject to given conditions. -pub struct InputMap -where S: Dsl, C: Command, I: DslInput, M: KeyMap + Send + Sync { - __: PhantomData<(S, C, I)>, - pub layers: Vec<(InputLayerCond, M)>, +pub struct InputMap<'source, + S, + C: Command + FromDsl<'source, S>, + I: DslInput, + M: KeyMap<'source, S, C, I> +> { + __: PhantomData<&'source (S, C, I)>, + pub layers: Vec<(InputLayerCond<'source, S>, M)>, } -impl Default for InputMap -where S: Dsl, C: Command, I: DslInput, M: KeyMap + Send + Sync { +impl<'source, + S, + C: Command + FromDsl<'source, S>, + I: DslInput, + M: KeyMap<'source, S, C, I> +> Default for InputMap<'source, S, C, I, M>{ fn default () -> Self { Self { __: PhantomData, layers: vec![] } } } -impl InputMap -where S: Dsl, C: Command, I: DslInput, M: KeyMap + Send + Sync { +impl<'source, + S, + C: Command + FromDsl<'source, S>, + I: DslInput, + M: KeyMap<'source, S, C, I> +> InputMap<'source, S, C, I, M> { pub fn new (keymap: M) -> Self { Self::default().layer(keymap) } @@ -93,26 +109,34 @@ where S: Dsl, C: Command, I: DslInput, M: KeyMap + Send + Sync { self.add_layer_if(Box::new(|_|Ok(true)), keymap); self } - pub fn layer_if (mut self, condition: InputLayerCond, keymap: M) -> Self { + pub fn layer_if (mut self, condition: InputLayerCond<'source, S>, keymap: M) -> Self { self.add_layer_if(condition, keymap); self } - pub fn add_layer_if (&mut self, condition: InputLayerCond, keymap: M) -> &mut Self { + pub fn add_layer_if (&mut self, condition: InputLayerCond<'source, S>, keymap: M) -> &mut Self { self.layers.push((Box::new(condition), keymap)); self } } -impl std::fmt::Debug for InputMap -where S: Dsl, C: Command, I: DslInput, M: KeyMap + Send + Sync { +impl<'source, + S, + C: Command + FromDsl<'source, S>, + I: DslInput, + M: KeyMap<'source, S, C, I> +> std::fmt::Debug for InputMap<'source, S, C, I, M> { fn fmt (&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { write!(f, "[InputMap: {} layer(s)]", self.layers.len()) } } /// An [InputMap] can be a [KeyMap]. -impl KeyMap for InputMap -where S: Dsl, C: Command, I: DslInput, M: KeyMap + Send + Sync { +impl<'source, + S, + C: Command + FromDsl<'source, S>, + I: DslInput, + M: KeyMap<'source, S, C, I> +> KeyMap<'source, S, C, I> for InputMap<'source, S, C, I, M> { fn keybind_resolve (&self, state: &S, input: &I) -> Perhaps { for (condition, keymap) in self.layers.iter() { if !condition(state)? { diff --git a/input/src/input_handle.rs b/input/src/input_handle.rs index 99bce29..2be276c 100644 --- a/input/src/input_handle.rs +++ b/input/src/input_handle.rs @@ -2,7 +2,7 @@ use crate::*; use std::sync::{Mutex, Arc, RwLock}; /// Event source -pub trait Input: Send + Sync + Sized { +pub trait Input: Sized { /// Type of input event type Event; /// Result of handling input @@ -36,7 +36,7 @@ pub trait Input: Send + Sync + Sized { } /// Handle input -pub trait Handle: Send + Sync { +pub trait Handle { fn handle (&mut self, _input: &E) -> Perhaps { Ok(None) } diff --git a/output/src/ops/align.rs b/output/src/ops/align.rs index 9d902ad..5702a40 100644 --- a/output/src/ops/align.rs +++ b/output/src/ops/align.rs @@ -36,39 +36,33 @@ pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W } pub struct Align(Alignment, A); #[cfg(feature = "dsl")] -impl, A> FromDsl for Align { - fn take_from <'state, 'source: 'state> (state: &'state State, iter: &mut TokenIter<'source>) - -> Perhaps - { - if let Some(Token { value: Value::Key(key), .. }) = iter.peek() { - match key { - "align/c"|"align/x"|"align/y"| - "align/n"|"align/s"|"align/e"|"align/w"| - "align/nw"|"align/sw"|"align/ne"|"align/se" => { - let _ = iter.next().unwrap(); - let content = state.take_or_fail(&mut iter.clone(), "expected content")?; - return Ok(Some(match key { - "align/c" => Self::c(content), - "align/x" => Self::x(content), - "align/y" => Self::y(content), - "align/n" => Self::n(content), - "align/s" => Self::s(content), - "align/e" => Self::e(content), - "align/w" => Self::w(content), - "align/nw" => Self::nw(content), - "align/ne" => Self::ne(content), - "align/sw" => Self::sw(content), - "align/se" => Self::se(content), - _ => unreachable!() - })) - }, - _ => return Ok(None) - } - } else { - Ok(None) - } +from_dsl!(@a: Align: |state, iter|if let Some(Token { value: Value::Key(key), .. }) = iter.peek() { + match key { + "align/c"|"align/x"|"align/y"| + "align/n"|"align/s"|"align/e"|"align/w"| + "align/nw"|"align/sw"|"align/ne"|"align/se" => { + let _ = iter.next().unwrap(); + let content = state.take_or_fail(&mut iter.clone(), "expected content")?; + return Ok(Some(match key { + "align/c" => Self::c(content), + "align/x" => Self::x(content), + "align/y" => Self::y(content), + "align/n" => Self::n(content), + "align/s" => Self::s(content), + "align/e" => Self::e(content), + "align/w" => Self::w(content), + "align/nw" => Self::nw(content), + "align/ne" => Self::ne(content), + "align/sw" => Self::sw(content), + "align/se" => Self::se(content), + _ => unreachable!() + })) + }, + _ => return Ok(None) } -} +} else { + Ok(None) +}); impl Align { #[inline] pub const fn c (a: A) -> Self { Self(Alignment::Center, a) } @@ -85,7 +79,7 @@ impl Align { } impl> Content for Align { - fn content (&self) -> impl Render { + fn content (&self) -> impl Render + '_ { &self.1 } fn layout (&self, on: E::Area) -> E::Area { diff --git a/output/src/ops/bsp.rs b/output/src/ops/bsp.rs index 7e961dd..6062485 100644 --- a/output/src/ops/bsp.rs +++ b/output/src/ops/bsp.rs @@ -21,39 +21,35 @@ impl, B: Content> Content for Bsp { } } #[cfg(feature = "dsl")] -impl + Dsl> FromDsl for Bsp { - fn take_from <'state, 'source: 'state> (state: &'state T, iter: &mut TokenIter<'source>) -> Perhaps { - Ok(if let Some(Token { - value: Value::Key("bsp/n"|"bsp/s"|"bsp/e"|"bsp/w"|"bsp/a"|"bsp/b"), - .. - }) = iter.peek() { - let base = iter.clone(); - return Ok(Some(match iter.next() { - Some(Token { value: Value::Key("bsp/n"), .. }) => - Self::n(state.take_or_fail(iter, "expected content 1")?, - state.take_or_fail(iter, "expected content 2")?), - Some(Token { value: Value::Key("bsp/s"), .. }) => - Self::s(state.take_or_fail(iter, "expected content 1")?, - state.take_or_fail(iter, "expected content 2")?), - Some(Token { value: Value::Key("bsp/e"), .. }) => - Self::e(state.take_or_fail(iter, "expected content 1")?, - state.take_or_fail(iter, "expected content 2")?), - Some(Token { value: Value::Key("bsp/w"), .. }) => - Self::w(state.take_or_fail(iter, "expected content 1")?, - state.take_or_fail(iter, "expected content 2")?), - Some(Token { value: Value::Key("bsp/a"), .. }) => - Self::a(state.take_or_fail(iter, "expected content 1")?, - state.take_or_fail(iter, "expected content 2")?), - Some(Token { value: Value::Key("bsp/b"), .. }) => - Self::b(state.take_or_fail(iter, "expected content 1")?, - state.take_or_fail(iter, "expected content 2")?), - _ => unreachable!(), - })) - } else { - None - }) - } -} +from_dsl!(@ab: Bsp: |state, iter|Ok(if let Some(Token { + value: Value::Key("bsp/n"|"bsp/s"|"bsp/e"|"bsp/w"|"bsp/a"|"bsp/b"), + .. +}) = iter.peek() { + let base = iter.clone(); + return Ok(Some(match iter.next() { + Some(Token { value: Value::Key("bsp/n"), .. }) => + Self::n(state.take_or_fail(iter, "expected content 1")?, + state.take_or_fail(iter, "expected content 2")?), + Some(Token { value: Value::Key("bsp/s"), .. }) => + Self::s(state.take_or_fail(iter, "expected content 1")?, + state.take_or_fail(iter, "expected content 2")?), + Some(Token { value: Value::Key("bsp/e"), .. }) => + Self::e(state.take_or_fail(iter, "expected content 1")?, + state.take_or_fail(iter, "expected content 2")?), + Some(Token { value: Value::Key("bsp/w"), .. }) => + Self::w(state.take_or_fail(iter, "expected content 1")?, + state.take_or_fail(iter, "expected content 2")?), + Some(Token { value: Value::Key("bsp/a"), .. }) => + Self::a(state.take_or_fail(iter, "expected content 1")?, + state.take_or_fail(iter, "expected content 2")?), + Some(Token { value: Value::Key("bsp/b"), .. }) => + Self::b(state.take_or_fail(iter, "expected content 1")?, + state.take_or_fail(iter, "expected content 2")?), + _ => unreachable!(), + })) +} else { + None +})); impl Bsp { #[inline] pub const fn n (a: A, b: B) -> Self { Self(North, a, b) } #[inline] pub const fn s (a: A, b: B) -> Self { Self(South, a, b) } diff --git a/output/src/ops/cond.rs b/output/src/ops/cond.rs index ca5ea61..e0dde77 100644 --- a/output/src/ops/cond.rs +++ b/output/src/ops/cond.rs @@ -18,8 +18,8 @@ impl Either { } } #[cfg(feature = "dsl")] -impl + Dsl> FromDsl for When { - fn take_from <'state, 'source: 'state> ( +impl<'source, A, T: Dsl + Dsl> FromDsl<'source, T> for When { + fn take_from <'state> ( state: &'state T, token: &mut TokenIter<'source> ) -> Perhaps { @@ -56,8 +56,8 @@ impl> Content for When { } } #[cfg(feature = "dsl")] -impl + Dsl + Dsl> FromDsl for Either { - fn take_from <'state, 'source: 'state> ( +impl<'source, A, B, T: Dsl + Dsl + Dsl> FromDsl<'source, T> for Either { + fn take_from <'state> ( state: &'state T, token: &mut TokenIter<'source> ) -> Perhaps { diff --git a/output/src/ops/thunk.rs b/output/src/ops/thunk.rs index 9d2c0bf..d0e2877 100644 --- a/output/src/ops/thunk.rs +++ b/output/src/ops/thunk.rs @@ -2,72 +2,67 @@ use crate::*; use std::marker::PhantomData; /// Lazily-evaluated [Render]able. -pub struct Thunk, F: Fn()->T + Send + Sync>( +pub struct Thunk, F: Fn()->T>( PhantomData, F ); -impl, F: Fn()->T + Send + Sync> Thunk { +impl, F: Fn()->T> Thunk { pub const fn new (thunk: F) -> Self { Self(PhantomData, thunk) } } -impl, F: Fn()->T + Send + Sync> Content for Thunk { +impl, F: Fn()->T> Content for Thunk { fn content (&self) -> impl Render { (self.1)() } } -pub struct ThunkBox<'a, E: Output>( +pub struct ThunkBox( PhantomData, - BoxRenderBox<'a, E> + Send + Sync + 'a> + BoxBox>>, ); -impl<'a, E: Output> ThunkBox<'a, E> { - pub const fn new (thunk: BoxRenderBox<'a, E> + Send + Sync + 'a>) -> Self { +impl ThunkBox { + pub const fn new (thunk: BoxBox>>) -> Self { Self(PhantomData, thunk) } } -impl<'a, E: Output> Content for ThunkBox<'a, E> { - fn content (&self) -> impl Render { (self.1)() } +impl Content for ThunkBox { + fn content (&self) -> impl Render { (&self.1)() } } -impl<'a, E, F, T> From for ThunkBox<'a, E> -where - E: Output, - F: Fn()->T + Send + Sync + 'a, - T: Render + Send + Sync + 'a -{ - fn from (f: F) -> Self { - Self(PhantomData, Box::new(move||f().boxed())) +impl FromBox>>> for ThunkBox { + fn from (f: BoxBox>>) -> Self { + Self(PhantomData, f) } } -//impl<'a, E: Output, F: Fn()->Box + 'a> + Send + Sync + 'a> From for ThunkBox<'a, E> { +//impl<'a, E: Output, F: Fn()->Box + 'a> + 'a> From for ThunkBox<'a, E> { //fn from (f: F) -> Self { //Self(Default::default(), Box::new(f)) //} //} -pub struct ThunkRender(PhantomData, F); -impl ThunkRender { +pub struct ThunkRender(PhantomData, F); +impl ThunkRender { pub fn new (render: F) -> Self { Self(PhantomData, render) } } -impl Content for ThunkRender { +impl Content for ThunkRender { fn render (&self, to: &mut E) { (self.1)(to) } } pub struct ThunkLayout< E: Output, - F1: Fn(E::Area)->E::Area + Send + Sync, - F2: Fn(&mut E) + Send + Sync + F1: Fn(E::Area)->E::Area, + F2: Fn(&mut E) >( PhantomData, F1, F2 ); -implE::Area + Send + Sync, F2: Fn(&mut E) + Send + Sync> ThunkLayout { +implE::Area, F2: Fn(&mut E)> ThunkLayout { pub fn new (layout: F1, render: F2) -> Self { Self(PhantomData, layout, render) } } impl Content for ThunkLayout where E: Output, - F1: Fn(E::Area)->E::Area + Send + Sync, - F2: Fn(&mut E) + Send + Sync + F1: Fn(E::Area)->E::Area, + F2: Fn(&mut E) { fn layout (&self, to: E::Area) -> E::Area { (self.1)(to) } fn render (&self, to: &mut E) { (self.2)(to) } diff --git a/output/src/ops/transform.rs b/output/src/ops/transform.rs index c589bfd..808f56b 100644 --- a/output/src/ops/transform.rs +++ b/output/src/ops/transform.rs @@ -33,8 +33,8 @@ macro_rules! transform_xy { #[inline] pub const fn xy (item: A) -> Self { Self::XY(item) } } #[cfg(feature = "dsl")] - impl> FromDsl for $Enum { - fn take_from <'state, 'source: 'state> (state: &'state T, iter: &mut TokenIter<'source>) -> Perhaps { + impl<'source, A, T: Dsl> FromDsl<'source, T> for $Enum { + fn take_from <'state> (state: &'state T, iter: &mut TokenIter<'source>) -> Perhaps { if let Some(Token { value: Value::Key(k), .. }) = iter.peek() { let mut base = iter.clone(); return Ok(Some(match iter.next() { @@ -51,7 +51,7 @@ macro_rules! transform_xy { } } impl> Content for $Enum { - fn content (&self) -> impl Render { + fn content (&self) -> impl Render + '_ { match self { Self::X(item) => item, Self::Y(item) => item, @@ -77,8 +77,8 @@ macro_rules! transform_xy_unit { #[inline] pub const fn xy (x: U, y: U, item: A) -> Self { Self::XY(x, y, item) } } #[cfg(feature = "dsl")] - impl + Dsl> FromDsl for $Enum { - fn take_from <'state, 'source: 'state> (state: &'state T, iter: &mut TokenIter<'source>) -> Perhaps { + impl<'source, A, U: Coordinate, T: Dsl + Dsl> FromDsl<'source, T> for $Enum { + fn take_from <'state> (state: &'state T, iter: &mut TokenIter<'source>) -> Perhaps { Ok(if let Some(Token { value: Value::Key($x|$y|$xy), .. }) = iter.peek() { let mut base = iter.clone(); Some(match iter.next() { @@ -103,7 +103,7 @@ macro_rules! transform_xy_unit { } } impl> Content for $Enum { - fn content (&self) -> impl Render { + fn content (&self) -> impl Render + '_ { Some(match self { Self::X(_, content) => content, Self::Y(_, content) => content, diff --git a/output/src/output.rs b/output/src/output.rs index b5cc1fc..07c8ac2 100644 --- a/output/src/output.rs +++ b/output/src/output.rs @@ -29,8 +29,8 @@ pub trait Render { /// Write data to display. fn render (&self, output: &mut E); /// Perform type erasure, turning `self` into an opaque [RenderBox]. - fn boxed <'a> (self) -> RenderBox<'a, E> where Self: Send + Sync + Sized + 'a { - Box::new(self) as RenderBox<'a, E> + fn boxed <'a> (self) -> Box + 'a> where Self: Sized + 'a { + Box::new(self) as Box + 'a> } } @@ -47,20 +47,20 @@ impl> Render for C { /// Opaque pointer to a renderable living on the heap. /// /// Return this from [Content::content] to use dynamic dispatch. -pub type RenderBox<'a, E> = Box>; +pub type RenderBox = Box>; /// You can render from a box. -impl<'a, E: Output> Content for RenderBox<'a, E> { - fn content (&self) -> impl Render { self.deref() } +impl Content for RenderBox { + fn content (&self) -> impl Render + '_ { self.deref() } //fn boxed <'b> (self) -> RenderBox<'b, E> where Self: Sized + 'b { self } } /// Opaque pointer to a renderable. -pub type RenderDyn<'a, E> = dyn Render + Send + Sync + 'a; +pub type RenderDyn = dyn Render; /// You can render from an opaque pointer. -impl<'a, E: Output> Content for &RenderDyn<'a, E> where Self: Sized { - fn content (&self) -> impl Render { +impl Content for &RenderDyn where Self: Sized { + fn content (&self) -> impl Render + '_ { #[allow(suspicious_double_ref_op)] self.deref() } @@ -77,7 +77,7 @@ impl<'a, E: Output> Content for &RenderDyn<'a, E> where Self: Sized { /// Composable renderable with static dispatch. pub trait Content { /// Return a [Render]able of a specific type. - fn content (&self) -> impl Render { () } + fn content (&self) -> impl Render + '_ { () } /// Perform layout. By default, delegates to [Self::content]. fn layout (&self, area: E::Area) -> E::Area { self.content().layout(area) } /// Draw to output. By default, delegates to [Self::content]. @@ -86,7 +86,7 @@ pub trait Content { /// Every pointer to [Content] is a [Content]. impl> Content for &C { - fn content (&self) -> impl Render { (*self).content() } + fn content (&self) -> impl Render + '_ { (*self).content() } fn layout (&self, area: E::Area) -> E::Area { (*self).layout(area) } fn render (&self, output: &mut E) { (*self).render(output) } } @@ -98,7 +98,7 @@ impl Content for () { } impl> Content for Option { - fn content (&self) -> impl Render { + fn content (&self) -> impl Render + '_ { self.as_ref() } fn layout (&self, area: E::Area) -> E::Area { @@ -117,7 +117,7 @@ impl> Content for Option { // Implement for all [Output]s. (|$self:ident:$Struct:ty| $content:expr) => { impl Content for $Struct { - fn content (&$self) -> impl Render { Some($content) } + fn content (&$self) -> impl Render + '_ { Some($content) } } }; // Implement for specific [Output]. @@ -127,7 +127,7 @@ impl> Content for Option { |$content:expr) => { impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Output> for $Struct $(<$($($L)? $($T)?),+>)? { - fn content (&$self) -> impl Render<$Output> { $content } + fn content (&$self) -> impl Render<$Output> + '_ { $content } } }; } diff --git a/proc/src/proc_command.rs b/proc/src/proc_command.rs index 9d83f9f..a8ca8c9 100644 --- a/proc/src/proc_command.rs +++ b/proc/src/proc_command.rs @@ -84,7 +84,7 @@ impl ToTokens for CommandDef { let mut out = TokenStream2::new(); for (arg, ty) in arm.args() { write_quote_to(&mut out, quote! { - #arg: Dsl::take_or_fail(self, words)?, + #arg: FromDsl::take_from_or_fail(self, words)?, }); } out @@ -137,17 +137,22 @@ impl ToTokens for CommandDef { #[derive(Clone, Debug)] pub enum #command_enum { #(#variants)* } /// Not generated by [tengri_proc]. #block - /// Generated by [tengri_proc]. + /// Generated by [tengri_proc::command]. + /// + /// Means [#command_enum] is now a [Command] over [#state]. + /// Instances of [#command_enum] can be consumed by a + /// mutable pointer to [#state], invoking predefined operations + /// and optionally returning undo history data. impl ::tengri::input::Command<#state> for #command_enum { fn execute (self, state: &mut #state) -> Perhaps { match self { #(#implementations)* } } } - /// Generated by [tengri_proc]. - impl ::tengri::dsl::FromDsl<#state> for #command_enum { - fn take_from <'state, 'source: 'state> ( + /// Generated by [tengri_proc::command]. + impl<'source> ::tengri::dsl::FromDsl<'source, #state> for #command_enum { + fn take_from <'state> ( state: &'state #state, - words: &mut TokenIter<'source>, + words: &mut ::tengri::dsl::TokenIter<'source> ) -> Perhaps { let mut words = words.clone(); let token = words.next(); diff --git a/proc/src/proc_expose.rs b/proc/src/proc_expose.rs index 887121d..f7b934e 100644 --- a/proc/src/proc_expose.rs +++ b/proc/src/proc_expose.rs @@ -60,7 +60,7 @@ impl ToTokens for ExposeDef { impl ToTokens for ExposeImpl { fn to_tokens (&self, out: &mut TokenStream2) { let Self(block, exposed) = self; - let exposed_impl_type = &block.self_ty; + let state = &block.self_ty; write_quote_to(out, quote! { #block }); for (t, variants) in exposed.iter() { let formatted_type = format!("{}", quote! { #t }); @@ -84,15 +84,15 @@ impl ToTokens for ExposeImpl { }; let values = variants.iter().map(ExposeArm::from); write_quote_to(out, quote! { - /// Generated by [tengriproc]. - impl ::tengri::dsl::Dsl<#t> for #exposed_impl_type { - fn take <'state, 'source: 'state> ( - &'state self, + /// Generated by [tengri_proc::expose]. + impl<'source> ::tengri::dsl::FromDsl<'source, #state> for #t { + fn take_from <'state> ( + state: &'state #state, words: &mut ::tengri::dsl::TokenIter<'source> - ) -> Perhaps<#t> { + ) -> Perhaps { Ok(Some(match words.next().map(|x|x.value) { #predefined - #(#values,)* + #(#values)* _ => return Ok(None) })) } @@ -116,7 +116,7 @@ impl ToTokens for ExposeArm { let Self(key, value) = self; let key = LitStr::new(&key, Span::call_site()); write_quote_to(out, quote! { - Some(::tengri::dsl::Value::Sym(#key)) => self.#value() + Some(::tengri::dsl::Value::Sym(#key)) => state.#value(), }) } } diff --git a/proc/src/proc_view.rs b/proc/src/proc_view.rs index 321fb26..70511eb 100644 --- a/proc/src/proc_view.rs +++ b/proc/src/proc_view.rs @@ -14,8 +14,6 @@ pub(crate) struct ViewImpl { exposed: BTreeMap, } -struct ViewArm(String, Ident); - impl Parse for ViewMeta { fn parse (input: ParseStream) -> Result { Ok(Self { @@ -41,6 +39,60 @@ impl Parse for ViewImpl { } } +impl ToTokens for ViewDef { + fn to_tokens (&self, out: &mut TokenStream2) { + let Self(ViewMeta { output }, ViewImpl { block, exposed }) = self; + let view = &block.self_ty; + let mut available = vec![]; + let exposed: Vec<_> = exposed.iter().map(|(key, value)|{ + available.push(key.clone()); + write_quote(quote! { #key => Some(state.#value().boxed()), }) + }).collect(); + let available: String = available.join(", "); + let error_msg = LitStr::new( + &format!("expected Sym(content), got: {{token:?}}, available: {available}"), + Span::call_site() + ); + write_quote_to(out, quote! { + #block + /// Generated by [tengri_proc]. + /// + /// Delegates the rendering of [#view] to the [#view::view} method, + /// which you will need to implement, e.g. passing a [TokenIter] + /// containing a layout and keybindings config from user dirs. + impl ::tengri::output::Content<#output> for #view { + fn content (&self) -> impl Render<#output> { + self.view() + } + } + /// Generated by [tengri_proc]. + /// + /// Gives [#view] the ability to construct the [Render]able + /// which might corresponds to a given [TokenStream], + /// while taking [#view]'s state into consideration. + impl<'source> ::tengri::dsl::FromDsl<'source, #view> for Box + 'source> { + fn take_from <'state> ( + state: &'state #view, + words: &mut ::tengri::dsl::TokenIter<'source>, + ) -> Perhaps { + Ok(words.peek().and_then(|::tengri::dsl::Token{ value, .. }|match value { + ::tengri::dsl::Value::Exp(_, exp) => { + todo!("builtin layout ops"); + //#builtins + None + }, + ::tengri::dsl::Value::Sym(sym) => match sym { + #(#exposed)* + _ => None + }, + _ => None + })) + } + } + }) + } +} + fn builtins () -> [TokenStream2;14] { [ quote! { When:: }, @@ -59,117 +111,3 @@ fn builtins () -> [TokenStream2;14] { quote! { Padding::<_, A> }, ] } - -impl ToTokens for ViewDef { - fn to_tokens (&self, out: &mut TokenStream2) { - let Self(ViewMeta { output }, ViewImpl { block, exposed }) = self; - let view = &block.self_ty; - let mut available = vec![]; - let exposed: Vec<_> = exposed.iter() - .map(|(k,v)|{ available.push(k.clone()); ViewArm(k.clone(), v.clone()) }) - .collect(); - let available: String = available.join(", "); - let error_msg = LitStr::new( - &format!("expected Sym(content), got: {{token:?}}, available: {available}"), - Span::call_site() - ); - for token in quote! { - #block - /// Generated by [tengri_proc]. - /// - /// Delegates the rendering of [#view] to the [#view::view} method, - /// which you will need to implement, e.g. passing a [TokenIter] - /// containing a layout and keybindings config from user dirs. - impl ::tengri::output::Content<#output> for #view { - fn content (&self) -> impl Render<#output> { - self.view() - } - } - /// Generated by [tengri_proc]. - /// - /// Gives [#view] the ability to construct the [Render]able - /// which might corresponds to a given [TokenStream], - /// while taking [#view]'s state into consideration. - impl<'context> ::tengri::dsl::FromDsl<#view> for RenderBox<'context, #output> { - fn take_from <'state, 'source: 'state> ( - state: &'state #view, words: &mut ::tengri::dsl::TokenIter<'source> - ) -> Perhaps { - Ok(match words.peek() { - Some(::tengri::dsl::Token { value: ::tengri::dsl::Value::Exp(exp), .. }) => { - if let Some(value) = FromDsl::take_from(state, words)? { - return Ok(Some(value.boxed())) - } - //#builtins - None - }, - #(#exposed)* - _ => None - }) - } - } - } { - out.append(token) - } - } -} - -impl ToTokens for ViewArm { - fn to_tokens (&self, out: &mut TokenStream2) { - let Self(key, value) = self; - out.append(Ident::new("Some", Span::call_site())); - out.append(Group::new(Delimiter::Parenthesis, { - let mut out = TokenStream2::new(); - out.append(Punct::new(':', Joint)); - out.append(Punct::new(':', Alone)); - out.append(Ident::new("tengri", Span::call_site())); - out.append(Punct::new(':', Joint)); - out.append(Punct::new(':', Alone)); - out.append(Ident::new("dsl", Span::call_site())); - out.append(Punct::new(':', Joint)); - out.append(Punct::new(':', Alone)); - out.append(Ident::new("Token", Span::call_site())); - out.append(Group::new(Delimiter::Brace, { - let mut out = TokenStream2::new(); - out.append(Ident::new("value", Span::call_site())); - out.append(Punct::new(':', Alone)); - out.append(Punct::new(':', Joint)); - out.append(Punct::new(':', Alone)); - out.append(Ident::new("tengri", Span::call_site())); - out.append(Punct::new(':', Joint)); - out.append(Punct::new(':', Alone)); - out.append(Ident::new("dsl", Span::call_site())); - out.append(Punct::new(':', Joint)); - out.append(Punct::new(':', Alone)); - out.append(Ident::new("Value", Span::call_site())); - out.append(Punct::new(':', Joint)); - out.append(Punct::new(':', Alone)); - out.append(Ident::new("Sym", Span::call_site())); - out.append(Group::new(Delimiter::Parenthesis, { - let mut out = TokenStream2::new(); - out.append(LitStr::new(key, Span::call_site()).token()); - out - })); - out.append(Punct::new(',', Alone)); - out.append(Punct::new('.', Joint)); - out.append(Punct::new('.', Alone)); - out - })); - out - })); - out.append(Punct::new('=', Joint)); - out.append(Punct::new('>', Alone)); - out.append(Ident::new("Some", Span::call_site())); - out.append(Group::new(Delimiter::Parenthesis, { - let mut out = TokenStream2::new(); - out.append(Ident::new("state", Span::call_site())); - out.append(Punct::new('.', Alone)); - out.append(value.clone()); - out.append(Group::new(Delimiter::Parenthesis, TokenStream2::new())); - out.append(Punct::new('.', Alone)); - out.append(Ident::new("boxed", Span::call_site())); - out.append(Group::new(Delimiter::Parenthesis, TokenStream2::new())); - out - })); - out.append(Punct::new(',', Alone)); - } -} diff --git a/tui/src/tui_engine.rs b/tui/src/tui_engine.rs index 0969cc3..b8d60f4 100644 --- a/tui/src/tui_engine.rs +++ b/tui/src/tui_engine.rs @@ -72,7 +72,8 @@ pub trait TuiRun + Handle + 'static> { fn run (&self, state: &Arc>) -> Usually<()>; } -impl + Handle + 'static> TuiRun for Arc> { +impl + Handle + Send + Sync + 'static> +TuiRun for Arc> { fn run (&self, state: &Arc>) -> Usually<()> { let _input_thread = TuiIn::run_input(self, state, Duration::from_millis(100)); self.write().unwrap().setup()?; diff --git a/tui/src/tui_engine/tui_input.rs b/tui/src/tui_engine/tui_input.rs index 75c5be2..c9cd788 100644 --- a/tui/src/tui_engine/tui_input.rs +++ b/tui/src/tui_engine/tui_input.rs @@ -21,7 +21,7 @@ impl Input for TuiIn { impl TuiIn { /// Spawn the input thread. - pub fn run_input + 'static> ( + pub fn run_input + Send + Sync + 'static> ( engine: &Arc>, state: &Arc>, timer: Duration