wip: big flat pt.2: extract engine crate

This commit is contained in:
🪞👃🪞 2024-12-30 17:54:30 +01:00
parent 4a3de618d0
commit a5628fb663
31 changed files with 1738 additions and 888 deletions

272
engine/src/output.rs Normal file
View file

@ -0,0 +1,272 @@
use crate::*;
use std::sync::{Arc, Mutex, RwLock};
/// Rendering target
pub trait Output<E: Engine> {
/// Current output area
fn area (&self) -> E::Area;
/// Mutable pointer to area
fn area_mut (&mut self) -> &mut E::Area;
/// Render widget in area
fn render_in (&mut self, area: E::Area, widget: &dyn Render<E>) -> Usually<()>;
}
/// Write content to output buffer.
pub trait Render<E: Engine>: Send + Sync {
/// Minimum size to use
fn min_size (&self, _: E::Size) -> Perhaps<E::Size> {
Ok(None)
}
/// Draw to output render target
fn render (&self, _: &mut E::Output) -> Usually<()> {
Ok(())
}
}
impl<E: Engine> Render<E> for &dyn Render<E> {}
impl<E: Engine> Render<E> for &mut dyn Render<E> {}
impl<E: Engine> Render<E> for Box<dyn Render<E>> {}
impl<E: Engine, R: Render<E>> Render<E> for &R {}
impl<E: Engine, R: Render<E>> Render<E> for &mut R {}
impl<E: Engine, R: Render<E>> Render<E> for Option<R> {}
impl<E: Engine, R: Render<E>> Render<E> for Arc<R> {}
impl<E: Engine, R: Render<E>> Render<E> for Mutex<R> {}
impl<E: Engine, R: Render<E>> Render<E> for RwLock<R> {}
/// Something that can be represented by a renderable component.
pub trait Content<E: Engine>: Render<E> + Send + Sync {
fn content (&self) -> Option<impl Render<E>> where (): Render<E> {
None::<()>
}
}
impl<E: Engine> Content<E> for &dyn Render<E> {}
impl<E: Engine> Content<E> for &mut dyn Render<E> {}
impl<E: Engine> Content<E> for Box<dyn Render<E>> {}
impl<E: Engine, C: Content<E>> Content<E> for &C {}
impl<E: Engine, C: Content<E>> Content<E> for &mut C {}
impl<E: Engine, C: Content<E>> Content<E> for Option<C> {}
impl<E: Engine, C: Content<E>> Content<E> for Arc<C> {}
impl<E: Engine, C: Content<E>> Content<E> for Mutex<C> {}
impl<E: Engine, C: Content<E>> Content<E> for RwLock<C> {}
/****
impl<E: Engine, R: Render<E> + Send + Sync> Content<E> for R {}
//impl<E: Engine, R: Render<E>> Content<E> for R {
//fn content (&self) -> Option<impl Render<E>> {
//Some(self)
//}
//}
/// All implementors of [Content] can be [Render]ed.
impl<E: Engine, C: Content<E>> Render<E> for C {
/// Minimum size to use
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
self.content().map(|content|content.min_size(to))
.unwrap_or(Ok(None))
}
/// Draw to output render target
fn render (&self, to: &mut E::Output) -> Usually<()> {
self.content().map(|content|content.render(to))
.unwrap_or(Ok(()))
}
}
//impl<E: Engine, C: Content<E>> Content<E> for &C {
//fn content (&self) -> Option<impl Render<E>> {
//Some(self)
//}
//}
//impl<E: Engine, C: Content<E>> Content<E> for Option<C> {
//fn content (&self) -> Option<impl Render<E>> {
//Some(self)
//}
//}
/// Define custom content for a struct.
#[macro_export] macro_rules! render {
// Implement for all engines
(|$self:ident:$Struct:ident$(<$($L:lifetime),*E$(,$T:ident$(:$U:path)?)*$(,)?>)?|$cb:expr) => {
impl<E: Engine, $($($L),*$($T $(: $U)?),*)?> Content<E> for $Struct $(<$($L,)* E, $($T),*>)? {
fn content (&$self) -> Option<impl Render<$E>> {
Some($cb)
}
}
};
// Implement for a specific engine
(<$E:ty>|$self:ident:$Struct:ident$(<
$($($L:lifetime),+)?
$($($T:ident$(:$U:path)?),+)?
>)?|$cb:expr) => {
impl $(<
$($($L),+)?
$($($T$(:$U)?),+)?
>)? Content<$E> for $Struct $(<
$($($L),+)?
$($($T),+)?
>)? {
fn content (&$self) -> Option<impl Render<$E>> {
Some($cb)
}
}
}
}
impl<E: Engine, R: Render<E>> Render<E> for &R {
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
(*self).min_size(to)
}
fn render (&self, to: &mut E::Output) -> Usually<()> {
(*self).render(to)
}
}
impl<E: Engine, R: Render<E>> Render<E> for Option<R> {
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
self.map(|content|content.min_size(to))
.unwrap_or(Ok(None))
}
fn render (&self, to: &mut E::Output) -> Usually<()> {
self.map(|content|content.render(to))
.unwrap_or(Ok(()))
}
}
//impl<E: Engine> Render<E> for &dyn Render<E> {
//fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
//(*self).min_size(to)
//}
//fn render (&self, to: &mut E::Output) -> Usually<()> {
//(*self).render(to)
//}
//}
//impl<E: Engine> Render<E> for &mut dyn Render<E> {
//fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
//(*self).min_size(to)
//}
//fn render (&self, to: &mut E::Output) -> Usually<()> {
//(*self).render(to)
//}
//}
//impl<E: Engine> Render<E> for Box<dyn Render<E> + '_> {
//fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
//(**self).min_size(to)
//}
//fn render (&self, to: &mut E::Output) -> Usually<()> {
//(**self).render(to)
//}
//}
//impl<E: Engine, W: Render<E>> Render<E> for Arc<W> {
//fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
//self.as_ref().min_size(to)
//}
//fn render (&self, to: &mut E::Output) -> Usually<()> {
//self.as_ref().render(to)
//}
//}
//impl<E: Engine, W: Render<E>> Render<E> for Mutex<W> {
//fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
//self.lock().unwrap().min_size(to)
//}
//fn render (&self, to: &mut E::Output) -> Usually<()> {
//self.lock().unwrap().render(to)
//}
//}
//impl<E: Engine, W: Render<E>> Render<E> for RwLock<W> {
//fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
//self.read().unwrap().min_size(to)
//}
//fn render (&self, to: &mut E::Output) -> Usually<()> {
//self.read().unwrap().render(to)
//}
//}
//impl<E: Engine, W: Render<E>> Render<E> for Option<W> {
//fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
//Ok(self.as_ref().map(|widget|widget.min_size(to)).transpose()?.flatten())
//}
//fn render (&self, to: &mut E::Output) -> Usually<()> {
//self.as_ref().map(|widget|widget.render(to)).unwrap_or(Ok(()))
//}
//}
/// Cast to dynamic pointer
pub fn widget <E, T> (w: &T) -> &dyn Render<E>
where E: Engine, T: Render<E>
{
w as &dyn Render<E>
}
/// Ad-hoc widget with custom rendering.
pub fn render <E, F> (render: F) -> impl Render<E>
where E: Engine, F: Fn(&mut E::Output)->Usually<()>+Send+Sync
{
Widget::new(|_|Ok(Some([0.into(),0.into()].into())), render)
}
/// A custom [Render] defined by passing layout and render closures in place.
pub struct Widget<
E: Engine,
L: Send + Sync + Fn(E::Size)->Perhaps<E::Size>,
R: Send + Sync + Fn(&mut E::Output)->Usually<()>
>(L, R, PhantomData<E>);
impl<
E: Engine,
L: Send + Sync + Fn(E::Size)->Perhaps<E::Size>,
R: Send + Sync + Fn(&mut E::Output)->Usually<()>
> Widget<E, L, R> {
pub fn new (layout: L, render: R) -> Self {
Self(layout, render, Default::default())
}
}
impl<
E: Engine,
L: Send + Sync + Fn(E::Size)->Perhaps<E::Size>,
R: Send + Sync + Fn(&mut E::Output)->Usually<()>
> Render<E> for Widget<E, L, R> {
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
self.0(to)
}
fn render (&self, to: &mut E::Output) -> Usually<()> {
self.1(to)
}
}
/// Has static methods for conditional rendering,
/// in unary and binary forms.
pub struct Cond;
impl Cond {
/// Render `item` when `cond` is true.
pub fn when <E: Engine, A: Render<E>> (cond: bool, item: A) -> When<E, A> {
When(cond, item, Default::default())
}
/// Render `item` if `cond` is true, otherwise render `other`.
pub fn either <E: Engine, A: Render<E>, B: Render<E>> (cond: bool, item: A, other: B) -> Either<E, A, B> {
Either(cond, item, other, Default::default())
}
}
/// Renders `self.1` when `self.0` is true.
pub struct When<E: Engine, A: Render<E>>(bool, A, PhantomData<E>);
/// Renders `self.1` when `self.0` is true, otherwise renders `self.2`
pub struct Either<E: Engine, A: Render<E>, B: Render<E>>(bool, A, B, PhantomData<E>);
**/