output: remove RenderBox
Some checks are pending
/ build (push) Waiting to run

This commit is contained in:
🪞👃🪞 2025-09-06 11:18:39 +03:00
parent 1c21a85f27
commit 194f2f9874
7 changed files with 16 additions and 29 deletions

View file

@ -1,7 +1,7 @@
//! ``` //! ```
//! use ::tengri::{output::*, tui::*}; //! use ::tengri::{output::*, tui::*};
//! let area: [u16;4] = [10, 10, 20, 20]; //! let area: [u16;4] = [10, 10, 20, 20];
//! fn test (area: [u16;4], item: &impl Content<TuiOut>, expected: [u16;4]) { //! fn test (area: [u16;4], item: &impl Render<TuiOut>, expected: [u16;4]) {
//! assert_eq!(Content::layout(item, area), expected); //! assert_eq!(Content::layout(item, area), expected);
//! assert_eq!(Render::layout(item, area), expected); //! assert_eq!(Render::layout(item, area), expected);
//! }; //! };

View file

@ -31,13 +31,6 @@ impl<E: Output, T: Content<E>> Content<E> for Option<T> {
} }
} }
/// You can render from a box.
impl<E: Output> Content<E> for RenderBox<E> {
fn content (&self) -> Option<impl Render<E> + '_> {
Some(self.deref())
}
}
/// You can render from an opaque pointer. /// You can render from an opaque pointer.
impl<E: Output> Content<E> for &dyn Render<E> where Self: Sized { impl<E: Output> Content<E> for &dyn Render<E> where Self: Sized {
fn content (&self) -> Option<impl Render<E> + '_> { fn content (&self) -> Option<impl Render<E> + '_> {

View file

@ -6,11 +6,10 @@ pub trait Render<E: Output> {
fn render (&self, output: &mut E); fn render (&self, output: &mut E);
/// Compute layout. /// Compute layout.
fn layout (&self, area: E::Area) -> E::Area { area } fn layout (&self, area: E::Area) -> E::Area { area }
/// Perform type erasure, turning `self` into an opaque [RenderBox].
fn boxed <'a> (self) -> Box<dyn Render<E> + 'a> where Self: Sized + 'a { fn boxed <'a> (self) -> Box<dyn Render<E> + 'a> where Self: Sized + 'a {
Box::new(self) as Box<dyn Render<E> + 'a> Box::new(self) as Box<dyn Render<E> + 'a>
} }
/// Perform type erasure, turning `self` into an opaque [Rc].
fn rc <'a> (self) -> Rc<dyn Render<E> + 'a> where Self: Sized + 'a { fn rc <'a> (self) -> Rc<dyn Render<E> + 'a> where Self: Sized + 'a {
Rc::new(self) as Rc<dyn Render<E> + 'a> Rc::new(self) as Rc<dyn Render<E> + 'a>
} }
@ -66,17 +65,12 @@ impl<E: Output, R: Render<E>> Render<E> for [R] {
} }
} }
/// Opaque pointer to a renderable that lives on the heap.
///
/// Return this from [Content::content] to use dynamic dispatch.
pub type RenderBox<E> = Box<dyn Render<E>>;
/// Implement custom rendering for a struct. /// Implement custom rendering for a struct.
#[macro_export] macro_rules! render { #[macro_export] macro_rules! render {
(|$self:ident:$Struct:ident $(< (|$self:ident:$Struct:ident $(<
$($L:lifetime),* $($T:ident $(:$Trait:path)?),* $($L:lifetime),* $($T:ident $(:$Trait:path)?),*
>)?, $to:ident | $render:expr) => { >)?, $to:ident | $render:expr) => {
impl <$($($L),*)? E: Output, $($T$(:$Trait)?),*> Content<E> impl <$($($L),*)? E: Output, $($T$(:$Trait)?),*> Render<E>
for $Struct $(<$($L),* $($T),*>>)? { for $Struct $(<$($L),* $($T),*>>)? {
fn render (&$self, $to: &mut E) { $render } fn render (&$self, $to: &mut E) { $render }
} }
@ -85,7 +79,7 @@ pub type RenderBox<E> = Box<dyn Render<E>>;
$self:ident: $self:ident:
$Struct:ident $(<$($($L:lifetime)? $($T:ident)? $(:$Trait:path)?),+>)?, $to:ident $Struct:ident $(<$($($L:lifetime)? $($T:ident)? $(:$Trait:path)?),+>)?, $to:ident
|$render:expr) => { |$render:expr) => {
impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Content<$Output> impl $(<$($($L)? $($T)? $(:$Trait)?),+>)? Render<$Output>
for $Struct $(<$($($L)? $($T)?),+>)? { for $Struct $(<$($($L)? $($T)?),+>)? {
fn render (&$self, $to: &mut $Output) { $render } fn render (&$self, $to: &mut $Output) { $render }
} }

View file

@ -146,7 +146,7 @@ proptest! {
() ()
} }
} }
impl Content<TestOutput> for String { impl Render<TestOutput> for String {
fn render (&self, to: &mut TestOutput) { fn render (&self, to: &mut TestOutput) {
to.area_mut().set_w(self.len() as u16); to.area_mut().set_w(self.len() as u16);
} }
@ -162,7 +162,7 @@ proptest! {
#[test] fn test_iter_map () { #[test] fn test_iter_map () {
struct Foo; struct Foo;
impl<T: Output> Content<T> for Foo {} impl<T: Output> Content<T> for Foo {}
fn _make_map <T: Output, U: Content<T> + Send + Sync> (data: &Vec<U>) -> impl Content<T> { fn _make_map <T: Output, U: Content<T> + Send + Sync> (data: &Vec<U>) -> impl Render<T> {
Map::new(||data.iter(), |_foo, _index|{}) Map::new(||data.iter(), |_foo, _index|{})
} }
let _data = vec![Foo, Foo, Foo]; let _data = vec![Foo, Foo, Foo];

View file

@ -106,7 +106,7 @@ pub(crate) fn write_quote_to (out: &mut TokenStream2, quote: TokenStream2) {
//#[tengri_proc::view(SomeOutput)] //#[tengri_proc::view(SomeOutput)]
//impl SomeView { //impl SomeView {
//#[tengri::view(":view-1")] //#[tengri::view(":view-1")]
//fn view_1 (&self) -> impl Content<SomeOutput> + use<'_> { //fn view_1 (&self) -> impl Render<SomeOutput> + use<'_> {
//"view-1" //"view-1"
//} //}
//} //}
@ -114,7 +114,7 @@ pub(crate) fn write_quote_to (out: &mut TokenStream2, quote: TokenStream2) {
//let written = quote! { #parsed }; //let written = quote! { #parsed };
//assert_eq!(format!("{written}"), format!("{}", quote! { //assert_eq!(format!("{written}"), format!("{}", quote! {
//impl SomeView { //impl SomeView {
//fn view_1 (&self) -> impl Content<SomeOutput> + use<'_> { //fn view_1 (&self) -> impl Render<SomeOutput> + use<'_> {
//"view-1" //"view-1"
//} //}
//} //}

View file

@ -76,25 +76,25 @@ content!(TuiOut: |self: Example|{
//#[tengri_proc::view(TuiOut)] //#[tengri_proc::view(TuiOut)]
//impl Example { //impl Example {
//pub fn title (&self) -> impl Content<TuiOut> + use<'_> { //pub fn title (&self) -> impl Render<TuiOut> + use<'_> {
//Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(format!("Example {}/{}:", self.0 + 1, EXAMPLES.len())))).boxed() //Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(format!("Example {}/{}:", self.0 + 1, EXAMPLES.len())))).boxed()
//} //}
//pub fn code (&self) -> impl Content<TuiOut> + use<'_> { //pub fn code (&self) -> impl Render<TuiOut> + use<'_> {
//Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", EXAMPLES[self.0])))).boxed() //Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", EXAMPLES[self.0])))).boxed()
//} //}
//pub fn hello (&self) -> impl Content<TuiOut> + use<'_> { //pub fn hello (&self) -> impl Render<TuiOut> + use<'_> {
//Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed() //Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed()
//} //}
//pub fn world (&self) -> impl Content<TuiOut> + use<'_> { //pub fn world (&self) -> impl Render<TuiOut> + use<'_> {
//Tui::bg(Color::Rgb(100, 10, 10), "world").boxed() //Tui::bg(Color::Rgb(100, 10, 10), "world").boxed()
//} //}
//pub fn hello_world (&self) -> impl Content<TuiOut> + use<'_> { //pub fn hello_world (&self) -> impl Render<TuiOut> + use<'_> {
//"Hello world!".boxed() //"Hello world!".boxed()
//} //}
//pub fn map_e (&self) -> impl Content<TuiOut> + use<'_> { //pub fn map_e (&self) -> impl Render<TuiOut> + use<'_> {
//Map::east(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed() //Map::east(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed()
//} //}
//pub fn map_s (&self) -> impl Content<TuiOut> + use<'_> { //pub fn map_s (&self) -> impl Render<TuiOut> + use<'_> {
//Map::south(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed() //Map::south(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed()
//} //}
//} //}

View file

@ -243,7 +243,7 @@ impl<T: FocusGrid + HasEnter> FocusOrder for T {
} }
pub trait FocusWrap<T> { pub trait FocusWrap<T> {
fn wrap <W: Content<TuiOut>> (self, focus: T, content: &'_ W) -> impl Content<TuiOut> + '_; fn wrap <W: Content<TuiOut>> (self, focus: T, content: &'_ W) -> impl Render<TuiOut> + '_;
} }
pub fn to_focus_command <T: Send + Sync> (input: &TuiIn) -> Option<FocusCommand<T>> { pub fn to_focus_command <T: Send + Sync> (input: &TuiIn) -> Option<FocusCommand<T>> {