From 62a0e8c17cc5ba6c19e5b5df533ec0b87f14ecb6 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sun, 5 Jan 2025 16:37:06 +0100 Subject: [PATCH] Box::deref makes the EDN rendering examples really work! --- edn/examples/edn01.edn | 2 +- edn/examples/edn01.rs | 2 +- edn/examples/edn02.rs | 6 ++- engine/src/input/handle.rs | 18 +++------ engine/src/output.rs | 71 ------------------------------------ engine/src/output/area.rs | 10 ++++- engine/src/output/content.rs | 27 ++++++++++++-- engine/src/output/render.rs | 51 +++++++++++++++++++++++++- engine/src/output/size.rs | 8 ++++ 9 files changed, 103 insertions(+), 92 deletions(-) diff --git a/edn/examples/edn01.edn b/edn/examples/edn01.edn index 27e8681e..7ff93d18 100644 --- a/edn/examples/edn01.edn +++ b/edn/examples/edn01.edn @@ -1 +1 @@ -:hello +:hello-world diff --git a/edn/examples/edn01.rs b/edn/examples/edn01.rs index 949df0cc..0fc3eb4d 100644 --- a/edn/examples/edn01.rs +++ b/edn/examples/edn01.rs @@ -14,7 +14,7 @@ pub struct Example; impl EdnLayout for &Example { fn get_content <'a> (&'a self, sym: &'a str) -> RenderBox<'a, Tui> { - Box::new(Thunk::new(move||if sym == ":hello" { "Hello world!" } else { "" })) + Box::new(Thunk::new(move||if sym == ":hello-world" { "Hello world!" } else { "" })) } } diff --git a/edn/examples/edn02.rs b/edn/examples/edn02.rs index 11e7962c..35e2466c 100644 --- a/edn/examples/edn02.rs +++ b/edn/examples/edn02.rs @@ -14,7 +14,11 @@ pub struct Example; impl EdnLayout for &Example { fn get_content <'a> (&'a self, sym: &'a str) -> RenderBox<'a, Tui> { - Box::new(Thunk::new(move||if sym == ":hello" { "Hello world!" } else { "" })) + Box::new(Thunk::new(move||match sym { + ":hello" => "Hello", + ":world" => "world", + _ => "" + })) } } diff --git a/engine/src/input/handle.rs b/engine/src/input/handle.rs index 15a9b5e1..751cc7fd 100644 --- a/engine/src/input/handle.rs +++ b/engine/src/input/handle.rs @@ -1,13 +1,6 @@ use crate::*; use std::sync::{Mutex, Arc, RwLock}; -/// Handle input -pub trait Handle: Send + Sync { - fn handle (&mut self, _input: &E::Input) -> Perhaps { - Ok(None) - } -} - #[macro_export] macro_rules! handle { (<$E:ty>|$self:ident:$Struct:ty,$input:ident|$handler:expr) => { impl Handle<$E> for $Struct { @@ -18,12 +11,17 @@ pub trait Handle: Send + Sync { } } +/// Handle input +pub trait Handle: Send + Sync { + fn handle (&mut self, _input: &E::Input) -> Perhaps { + Ok(None) + } +} impl> Handle for &mut H { fn handle (&mut self, context: &E::Input) -> Perhaps { (*self).handle(context) } } - impl> Handle for Option { fn handle (&mut self, context: &E::Input) -> Perhaps { if let Some(ref mut handle) = self { @@ -33,25 +31,21 @@ impl> Handle for Option { } } } - impl Handle for Mutex where H: Handle { fn handle (&mut self, context: &E::Input) -> Perhaps { self.get_mut().unwrap().handle(context) } } - impl Handle for Arc> where H: Handle { fn handle (&mut self, context: &E::Input) -> Perhaps { self.lock().unwrap().handle(context) } } - impl Handle for RwLock where H: Handle { fn handle (&mut self, context: &E::Input) -> Perhaps { self.write().unwrap().handle(context) } } - impl Handle for Arc> where H: Handle { fn handle (&mut self, context: &E::Input) -> Perhaps { self.write().unwrap().handle(context) diff --git a/engine/src/output.rs b/engine/src/output.rs index 2e891766..70c3ef98 100644 --- a/engine/src/output.rs +++ b/engine/src/output.rs @@ -22,74 +22,3 @@ pub trait Output { #[inline] fn h (&self) -> E::Unit { self.area().h() } #[inline] fn wh (&self) -> E::Size { self.area().wh().into() } } -impl> Content for &T { - fn content (&self) -> impl Render { - (*self).content() - } - fn layout (&self, area: E::Area) -> E::Area { - (*self).layout(area) - } - fn render (&self, output: &mut E::Output) { - (*self).render(output) - } -} -/// The platonic ideal unit of [Content]: total emptiness at dead center. -impl Content for () { - fn layout (&self, area: E::Area) -> E::Area { - let [x, y] = area.center(); - [x, y, 0.into(), 0.into()].into() - } - fn render (&self, _: &mut E::Output) {} -} -impl> Content for Option { - fn content (&self) -> impl Render { - self.as_ref() - } - fn layout (&self, area: E::Area) -> E::Area { - self.as_ref() - .map(|content|content.layout(area)) - .unwrap_or([0.into(), 0.into(), 0.into(), 0.into(),].into()) - } - fn render (&self, output: &mut E::Output) { - self.as_ref() - .map(|content|content.render(output)); - } -} - - -#[macro_export] macro_rules! render { - (($self:ident:$Struct:ty) => $content:expr) => { - impl Content for $Struct { - fn content (&$self) -> impl Render { Some($content) } - } - }; - (|$self:ident:$Struct:ident $(< - $($L:lifetime),* $($T:ident $(:$Trait:path)?),* - >)?, $to:ident | $render:expr) => { - impl <$($($L),*)? E: Engine, $($T$(:$Trait)?),*> Content - for $Struct $(<$($L),* $($T),*>>)? { - fn render (&$self, $to: &mut E::Output) { $render } - } - }; - ($Engine:ty: - ($self:ident:$Struct:ident $(<$( - $($L:lifetime)? $($T:ident)? $(:$Trait:path)? - ),+>)?) => $content:expr - ) => { - impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Engine> - for $Struct $(<$($($L)? $($T)?),+>)? { - fn content (&$self) -> impl Render<$Engine> { $content } - } - }; - - ($Engine:ty: - |$self:ident : $Struct:ident $(<$( - $($L:lifetime)? $($T:ident)? $(:$Trait:path)? - ),+>)?, $to:ident| $render:expr - ) => { - impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Engine> - for $Struct $(<$($($L)? $($T)?),+>)? { - fn render (&$self, $to: &mut <$Engine as Engine>::Output) { $render } - } - }; -} diff --git a/engine/src/output/area.rs b/engine/src/output/area.rs index f17bad73..6e5c5bea 100644 --- a/engine/src/output/area.rs +++ b/engine/src/output/area.rs @@ -64,9 +64,17 @@ pub trait Area: From<[N;4]> + Debug + Copy { #[inline] fn centered (&self) -> [N;2] { [self.x().minus(self.w()/2.into()), self.y().minus(self.h()/2.into())] } - fn zero () -> [N;4] { + #[inline] fn zero () -> [N;4] { [N::zero(), N::zero(), N::zero(), N::zero()] } + #[inline] fn from_position (pos: impl Size) -> [N;4] { + let [x, y] = pos.wh(); + [x, y, 0.into(), 0.into()] + } + #[inline] fn from_size (size: impl Size) -> [N;4] { + let [w, h] = size.wh(); + [0.into(), 0.into(), w, h] + } } impl Area for (N, N, N, N) { diff --git a/engine/src/output/content.rs b/engine/src/output/content.rs index cfec59c7..4487b684 100644 --- a/engine/src/output/content.rs +++ b/engine/src/output/content.rs @@ -6,7 +6,28 @@ pub trait Content: Send + Sync + Sized { fn layout (&self, area: E::Area) -> E::Area { self.content().layout(area) } fn render (&self, output: &mut E::Output) { self.content().render(output) } } -impl> Render for C { - fn layout (&self, area: E::Area) -> E::Area { Content::layout(self, area) } - fn render (&self, output: &mut E::Output) { Content::render(self, output) } +impl> Content for &C { + fn content (&self) -> impl Render { (*self).content() } + fn layout (&self, area: E::Area) -> E::Area { (*self).layout(area) } + fn render (&self, output: &mut E::Output) { (*self).render(output) } +} +/// The platonic ideal unit of [Content]: total emptiness at dead center. +impl Content for () { + fn layout (&self, area: E::Area) -> E::Area { area.center().to_area_pos().into() } + fn render (&self, _: &mut E::Output) {} +} + +impl> Content for Option { + fn content (&self) -> impl Render { + self.as_ref() + } + fn layout (&self, area: E::Area) -> E::Area { + self.as_ref() + .map(|content|content.layout(area)) + .unwrap_or([0.into(), 0.into(), 0.into(), 0.into(),].into()) + } + fn render (&self, output: &mut E::Output) { + self.as_ref() + .map(|content|content.render(output)); + } } diff --git a/engine/src/output/render.rs b/engine/src/output/render.rs index 1ab02953..202bb43f 100644 --- a/engine/src/output/render.rs +++ b/engine/src/output/render.rs @@ -1,4 +1,5 @@ use crate::*; +use std::ops::Deref; /// Custom layout and rendering. pub trait Render: Send + Sync { @@ -8,11 +9,57 @@ pub trait Render: Send + Sync { Box::new(self) as RenderBox<'a, E> } } + pub type RenderDyn<'a, Engine> = dyn Render + 'a; impl<'a, E: Engine> Content for &RenderDyn<'a, E> where Self: Sized { - fn content (&self) -> impl Render { self } + fn content (&self) -> impl Render { *self } + fn layout (&self, area: E::Area) -> E::Area { Render::layout(self.deref(), area) } + fn render (&self, output: &mut E::Output) { Render::render(self.deref(), output) } } + pub type RenderBox<'a, E: Engine> = Box>; impl<'a, E: Engine> Content for RenderBox<'a, E> { - fn content (&self) -> impl Render { self } + fn content (&self) -> impl Render { self.deref() } +} + +impl> Render for C { + fn layout (&self, area: E::Area) -> E::Area { Content::layout(self, area) } + fn render (&self, output: &mut E::Output) { Content::render(self, output) } +} + +#[macro_export] macro_rules! render { + (($self:ident:$Struct:ty) => $content:expr) => { + impl Content for $Struct { + fn content (&$self) -> impl Render { Some($content) } + } + }; + (|$self:ident:$Struct:ident $(< + $($L:lifetime),* $($T:ident $(:$Trait:path)?),* + >)?, $to:ident | $render:expr) => { + impl <$($($L),*)? E: Engine, $($T$(:$Trait)?),*> Content + for $Struct $(<$($L),* $($T),*>>)? { + fn render (&$self, $to: &mut E::Output) { $render } + } + }; + ($Engine:ty: + ($self:ident:$Struct:ident $(<$( + $($L:lifetime)? $($T:ident)? $(:$Trait:path)? + ),+>)?) => $content:expr + ) => { + impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Engine> + for $Struct $(<$($($L)? $($T)?),+>)? { + fn content (&$self) -> impl Render<$Engine> { $content } + } + }; + + ($Engine:ty: + |$self:ident : $Struct:ident $(<$( + $($L:lifetime)? $($T:ident)? $(:$Trait:path)? + ),+>)?, $to:ident| $render:expr + ) => { + impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Engine> + for $Struct $(<$($($L)? $($T)?),+>)? { + fn render (&$self, $to: &mut <$Engine as Engine>::Output) { $render } + } + }; } diff --git a/engine/src/output/size.rs b/engine/src/output/size.rs index cc5fa329..ea080d18 100644 --- a/engine/src/output/size.rs +++ b/engine/src/output/size.rs @@ -19,6 +19,14 @@ pub trait Size: From<[N;2]> + Debug + Copy { #[inline] fn zero () -> [N;2] { [N::zero(), N::zero()] } + #[inline] fn to_area_pos (&self) -> [N;4] { + let [x, y] = self.wh(); + [x, y, 0.into(), 0.into()] + } + #[inline] fn to_area_size (&self) -> [N;4] { + let [w, h] = self.wh(); + [0.into(), 0.into(), w, h] + } } impl Size for (N, N) {