From f033f9ff5423c26fc3248614d5837eb3eb0a367c Mon Sep 17 00:00:00 2001 From: same mf who else Date: Sat, 14 Feb 2026 20:14:27 +0200 Subject: [PATCH] wip: refactor(output): 91 more errors... --- output/src/lib.rs | 146 +++++++++++++++++++++++++++++-- output/src/out_impls.rs | 175 +++++++++++++++++++++----------------- output/src/out_macros.rs | 138 ------------------------------ output/src/out_structs.rs | 14 +-- output/src/out_traits.rs | 4 +- 5 files changed, 247 insertions(+), 230 deletions(-) delete mode 100644 output/src/out_macros.rs diff --git a/output/src/lib.rs b/output/src/lib.rs index 10348d7..65c7580 100644 --- a/output/src/lib.rs +++ b/output/src/lib.rs @@ -16,14 +16,150 @@ pub(crate) use std::sync::{Arc, RwLock, atomic::{AtomicUsize, Ordering::Relaxed} pub(crate) use std::marker::PhantomData; pub(crate) use dizzle::*; -mod out_macros; // Must be defined first +// Define macros first, so that private macros are available in private modules. + +/// Clear a pre-allocated buffer, then write into it. +#[macro_export] macro_rules! rewrite { + ($buf:ident, $($rest:tt)*) => { |$buf,_,_|{ $buf.clear(); write!($buf, $($rest)*) } } +} + +/// FIXME: This macro should be some variant of `eval`, too. +/// But taking into account the different signatures (resolving them into 1?) +#[cfg(feature = "dsl")] #[macro_export] macro_rules! draw { + ($State:ident: $Output:ident: $layers:expr) => { + impl Draw<$Output> for $State { + fn draw (&self, to: &mut $Output) { + for layer in $layers { layer(self, to) } + } + } + } +} + +/// FIXME: This is generic: should be called `eval` and be part of [dizzle]. +#[cfg(feature = "dsl")] #[macro_export] macro_rules! view { + ($State:ident: $Output:ident: $namespaces:expr) => { + impl View<$Output, ()> for $State { + fn view_expr <'a> (&'a self, to: &mut $Output, expr: &'a impl Expression) -> Usually<()> { + for namespace in $namespaces { if namespace(self, to, expr)? { return Ok(()) } } + Err(format!("{}::<{}, ()>::view_expr: unexpected: {expr:?}", + stringify! { $State }, + stringify! { $Output }).into()) + } + } + } +} + +/// Stack things on top of each other, +#[macro_export] macro_rules! lay (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::b(bsp, $expr);)*; bsp }}); + +/// Stack southward. +#[macro_export] macro_rules! col (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::s(bsp, $expr);)*; bsp }}); + +/// Stack northward. +#[macro_export] macro_rules! col_up (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::n(bsp, $expr);)*; bsp }}); + +/// Stack eastward. +#[macro_export] macro_rules! row (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::e(bsp, $expr);)*; bsp }}); + +/// Define layout operation. +macro_rules! layout_op_xy ( + // Variant for layout ops that take no coordinates + (0: $T: ident) => { + impl $T { + #[inline] pub const fn inner (&self) -> &A { + match self { Self::X(c) | Self::Y(c) | Self::XY(c) => c } + } + } + impl> Draw for $T { + fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) } + } + }; + // Variant for layout ops that take one coordinate + (1: $T: ident) => { + impl $T { + #[inline] pub const fn inner (&self) -> &A { + match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c, } + } + } + impl> Draw for $T { + fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) } + } + impl $T { + #[inline] pub fn dx (&self) -> U { + match self { Self::X(x, _) | Self::XY(x, ..) => *x, _ => 0.into() } + } + #[inline] pub fn dy (&self) -> U { + match self { Self::Y(y, _) | Self::XY(y, ..) => *y, _ => 0.into() } + } + } + }; + (1 opt: $T: ident) => { + impl $T { + #[inline] pub const fn inner (&self) -> &A { + match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c, } + } + } + impl> Draw for $T { + fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) } + } + impl $T { + #[inline] pub const fn dx (&self) -> Option { + match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } + } + #[inline] pub const fn dy (&self) -> Option { + match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } + } + } + }; +); + +// Implement layout op that increments X and/or Y by fixed amount. +macro_rules! push_pull(($T:ident: $method: ident)=>{ + layout_op_xy!(1: $T); + impl> Layout for $T { + fn x (&self, area: O::Area) -> O::Unit { area.x().$method(self.dx()) } + fn y (&self, area: O::Area) -> O::Unit { area.y().$method(self.dy()) } + } +}); + +macro_rules! impl_map_direction (($name:ident, $axis:ident, $align:ident)=>{ + impl<'a, O, A, B, I, F> Map< + O, A, Push>>>, I, F, fn(A, usize)->B + > where + O: Out, + B: Draw, + I: Iterator + Send + Sync + 'a, + F: Fn() -> I + Send + Sync + 'a + { + pub const fn $name ( + size: O::Unit, + get_iter: F, + get_item: impl Fn(A, usize)->B + Send + Sync + ) -> Map< + O, A, + Push>>, + I, F, + impl Fn(A, usize)->Push>> + Send + Sync + > { + Map { + __: PhantomData, + get_iter, + get_item: move |item: A, index: usize|{ + // FIXME: multiply + let mut push: O::Unit = O::Unit::from(0u16); + for _ in 0..index { + push = push + size; + } + Push::$axis(push, Align::$align(Fixed::$axis(size, get_item(item, index)))) + } + } + } + } +}); + mod out_traits; pub use self::out_traits::*; mod out_structs; pub use self::out_structs::*; mod out_impls; pub use self::out_impls::*; - -mod widget; pub use self::widget::*; -mod layout; pub use self::layout::*; - #[cfg(test)] mod out_tests; #[cfg(feature = "dsl")] diff --git a/output/src/out_impls.rs b/output/src/out_impls.rs index 8dcab55..c8c3189 100644 --- a/output/src/out_impls.rs +++ b/output/src/out_impls.rs @@ -1,4 +1,6 @@ use crate::*; +use Direction::*; +use Alignment::*; impl Coord for u16 { fn plus (self, other: Self) -> Self { self.saturating_add(other) } @@ -9,11 +11,35 @@ impl HasXY for XY { fn y (&self) -> N { self.1 } } +impl HasXY for XYWH { + fn x (&self) -> N { self.0 } + fn y (&self) -> N { self.1 } +} + +impl HasXY for O { + // X coordinate of output area + #[inline] fn x (&self) -> O::Unit { self.area().x() } + // Y coordinate of output area + #[inline] fn y (&self) -> O::Unit { self.area().y() } +} + impl HasWH for WH { fn w (&self) -> N { self.0 } fn h (&self) -> N { self.1 } } +impl HasWH for XYWH { + fn w (&self) -> N { self.2 } + fn h (&self) -> N { self.3 } +} + +impl HasWH for O { + // Width of output area + #[inline] fn w (&self) -> O::Unit { self.area().w() } + // Height of output area + #[inline] fn h (&self) -> O::Unit { self.area().h() } +} + impl WH { fn clip_w (&self, w: N) -> [N;2] { [self.w().min(w), self.h()] } fn clip_h (&self, h: N) -> [N;2] { [self.w(), self.h().min(h)] } @@ -24,48 +50,49 @@ impl WH { Ok(self) } } - impl XYWH { - fn from_position (pos: impl Size) -> Self { - let [x, y] = pos.wh(); - [x, y, 0.into(), 0.into()] - } - fn from_size (size: impl Size) -> Self { - let [w, h] = size.wh(); - [0.into(), 0.into(), w, h] - } - fn lrtb (&self) -> [N;4] { - [self.x(), self.x2(), self.y(), self.y2()] - } - fn center (&self) -> XY { - [self.x().plus(self.w()/2.into()), self.y().plus(self.h()/2.into())] - } - fn centered (&self) -> XY { - [self.x().minus(self.w()/2.into()), self.y().minus(self.h()/2.into())] - } - fn centered_x (&self, n: N) -> XYWH { - let [x, y, w, h] = self.xywh(); - [(x.plus(w / 2.into())).minus(n / 2.into()), y.plus(h / 2.into()), n, 1.into()] - } - fn centered_y (&self, n: N) -> XYWH { - let [x, y, w, h] = self.xywh(); - [x.plus(w / 2.into()), (y.plus(h / 2.into())).minus(n / 2.into()), 1.into(), n] - } - fn centered_xy (&self, [n, m]: [N;2]) -> XYWH { - let [x, y, w, h] = self.xywh(); - [(x.plus(w / 2.into())).minus(n / 2.into()), (y.plus(h / 2.into())).minus(m / 2.into()), n, m] - } + /// Iterate over every covered X coordinate. fn iter_x (&self) -> impl Iterator where N: std::iter::Step { self.x()..(self.x()+self.w()) } + /// Iterate over every covered Y coordinate. fn iter_y (&self) -> impl Iterator where N: std::iter::Step { self.y()..(self.y()+self.h()) } - fn clipped (&self, wh: impl Size) -> XYWH { - [self.x(), self.y(), wh.w(), wh.h()] + fn from_position (pos: impl HasWH) -> Self { + let [x, y] = pos.wh(); + Self(x, y, 0.into(), 0.into()) + } + fn from_size (size: impl HasWH) -> Self { + let [w, h] = size.wh(); + Self(0.into(), 0.into(), w, h) + } + fn lrtb (&self) -> [N;4] { + Self(self.x(), self.x2(), self.y(), self.y2()) + } + fn center (&self) -> XY { + Self(self.x().plus(self.w()/2.into()), self.y().plus(self.h()/2.into())) + } + fn centered (&self) -> XY { + Self(self.x().minus(self.w()/2.into()), self.y().minus(self.h()/2.into())) + } + fn centered_x (&self, n: N) -> XYWH { + let [x, y, w, h] = self.xywh(); + Self((x.plus(w / 2.into())).minus(n / 2.into()), y.plus(h / 2.into()), n, 1.into()) + } + fn centered_y (&self, n: N) -> XYWH { + let [x, y, w, h] = self.xywh(); + Self(x.plus(w / 2.into()), (y.plus(h / 2.into())).minus(n / 2.into()), 1.into(), n) + } + fn centered_xy (&self, [n, m]: [N;2]) -> XYWH { + let [x, y, w, h] = self.xywh(); + Self((x.plus(w / 2.into())).minus(n / 2.into()), (y.plus(h / 2.into())).minus(m / 2.into()), n, m) + } + fn clipped (&self, wh: impl HasWH) -> XYWH { + Self(self.x(), self.y(), wh.w(), wh.h()) } fn clipped_h (&self, h: N) -> XYWH { - [self.x(), self.y(), self.w(), self.h().min(h)] + Self(self.x(), self.y(), self.w(), self.h().min(h)) } fn clipped_w (&self, w: N) -> XYWH { [self.x(), self.y(), self.w().min(w), self.h()] @@ -77,31 +104,6 @@ impl XYWH { [self.x(), self.y(), self.w(), h] } } - -impl HasXY for XYWH { - fn x (&self) -> N { self.0 } - fn y (&self) -> N { self.1 } -} - -impl HasWH for XYWH { - fn w (&self) -> N { self.2 } - fn h (&self) -> N { self.3 } -} - -impl super::ng::HasXY for O { - // X coordinate of output area - #[inline] fn x (&self) -> O::Unit { self.area().x() } - // Y coordinate of output area - #[inline] fn y (&self) -> O::Unit { self.area().y() } -} - -impl super::ng::HasWH for O { - // Width of output area - #[inline] fn w (&self) -> O::Unit { self.area().w() } - // Height of output area - #[inline] fn h (&self) -> O::Unit { self.area().h() } -} - impl + Layout> Content for T {} impl<'a, O: Out> AsRef + 'a> for dyn Content + 'a { @@ -190,8 +192,8 @@ impl Memo { } impl Direction { - pub fn split_fixed (self, area: impl Area, a: N) -> ([N;4],[N;4]) { - let [x, y, w, h] = area.xywh(); + pub fn split_fixed (self, area: impl HasXYWH, a: N) -> ([N;4],[N;4]) { + let XYWH(x, y, w, h) = area.xywh(); match self { North => ([x, y.plus(h).minus(a), w, a], [x, y, w, h.minus(a)]), South => ([x, y, w, a], [x, y.plus(a), w, h.minus(a)]), @@ -202,16 +204,6 @@ impl Direction { } } -impl Size for (N, N) { - fn x (&self) -> N { self.0 } - fn y (&self) -> N { self.1 } -} - -impl Size for [N;2] { - fn x (&self) -> N { self[0] } - fn y (&self) -> N { self[1] } -} - impl>> HasSize for T { fn size (&self) -> &Measure { self.get() @@ -513,11 +505,20 @@ impl> Layout for Align { } impl Pad { - #[inline] pub const fn inner (&self) -> &A { match self { X(_, c) | Y(_, c) | XY(_, _, c) => c, } } + #[inline] pub const fn inner (&self) -> &A { + use Pad::*; + match self { X(_, c) | Y(_, c) | XY(_, _, c) => c, } + } } impl Pad { - #[inline] pub fn dx (&self) -> U { match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, } } - #[inline] pub fn dy (&self) -> U { match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, } } + #[inline] pub fn dx (&self) -> U { + use Pad::*; + match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, } + } + #[inline] pub fn dy (&self) -> U { + use Pad::*; + match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, } + } } impl> Draw for Pad { fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) } @@ -567,13 +568,27 @@ impl, Tail: Content> Draw for Bsp { } } impl, Tail: Layout> Layout for Bsp { - fn w (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | North | South => self.1.w(area).max(self.2.w(area)), East | West => self.1.w_min(area).plus(self.2.w(area)), } } - fn w_min (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | North | South => self.1.w_min(area).max(self.2.w_min(area)), East | West => self.1.w_min(area).plus(self.2.w_min(area)), } } - fn w_max (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | North | South => self.1.w_max(area).max(self.2.w_max(area)), East | West => self.1.w_max(area).plus(self.2.w_max(area)), } } - fn h (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | East | West => self.1.h(area).max(self.2.h(area)), North | South => self.1.h(area).plus(self.2.h(area)), } } - fn h_min (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | East | West => self.1.h_min(area).max(self.2.h_min(area)), North | South => self.1.h_min(area).plus(self.2.h_min(area)), } } - fn h_max (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | North | South => self.1.h_max(area).max(self.2.h_max(area)), East | West => self.1.h_max(area).plus(self.2.h_max(area)), } } - fn layout (&self, area: O::Area) -> O::Area { bsp_areas(area, self.0, &self.1, &self.2)[2] } + fn w (&self, area: O::Area) -> O::Unit { + match self.0 { Above | Below | North | South => self.1.w(area).max(self.2.w(area)), East | West => self.1.w_min(area).plus(self.2.w(area)), } + } + fn w_min (&self, area: O::Area) -> O::Unit { + match self.0 { Above | Below | North | South => self.1.w_min(area).max(self.2.w_min(area)), East | West => self.1.w_min(area).plus(self.2.w_min(area)), } + } + fn w_max (&self, area: O::Area) -> O::Unit { + match self.0 { Above | Below | North | South => self.1.w_max(area).max(self.2.w_max(area)), East | West => self.1.w_max(area).plus(self.2.w_max(area)), } + } + fn h (&self, area: O::Area) -> O::Unit { + match self.0 { Above | Below | East | West => self.1.h(area).max(self.2.h(area)), North | South => self.1.h(area).plus(self.2.h(area)), } + } + fn h_min (&self, area: O::Area) -> O::Unit { + match self.0 { Above | Below | East | West => self.1.h_min(area).max(self.2.h_min(area)), North | South => self.1.h_min(area).plus(self.2.h_min(area)), } + } + fn h_max (&self, area: O::Area) -> O::Unit { + match self.0 { Above | Below | North | South => self.1.h_max(area).max(self.2.h_max(area)), East | West => self.1.h_max(area).plus(self.2.h_max(area)), } + } + fn layout (&self, area: O::Area) -> O::Area { + bsp_areas(area, self.0, &self.1, &self.2)[2] + } } fn bsp_areas , B: Layout> (area: O::Area, direction: Direction, a: &A, b: &B,) -> [O::Area;3] { diff --git a/output/src/out_macros.rs b/output/src/out_macros.rs deleted file mode 100644 index 2b7a8c6..0000000 --- a/output/src/out_macros.rs +++ /dev/null @@ -1,138 +0,0 @@ -/// Clear a pre-allocated buffer, then write into it. -#[macro_export] macro_rules! rewrite { - ($buf:ident, $($rest:tt)*) => { |$buf,_,_|{ $buf.clear(); write!($buf, $($rest)*) } } -} - -/// FIXME: This macro should be some variant of `eval`, too. -/// But taking into account the different signatures (resolving them into 1?) -#[cfg(feature = "dsl")] #[macro_export] macro_rules! draw { - ($State:ident: $Output:ident: $layers:expr) => { - impl Draw<$Output> for $State { - fn draw (&self, to: &mut $Output) { - for layer in $layers { layer(self, to) } - } - } - } -} - -/// FIXME: This is generic: should be called `eval` and be part of [dizzle]. -#[cfg(feature = "dsl")] #[macro_export] macro_rules! view { - ($State:ident: $Output:ident: $namespaces:expr) => { - impl View<$Output, ()> for $State { - fn view_expr <'a> (&'a self, to: &mut $Output, expr: &'a impl Expression) -> Usually<()> { - for namespace in $namespaces { if namespace(self, to, expr)? { return Ok(()) } } - Err(format!("{}::<{}, ()>::view_expr: unexpected: {expr:?}", - stringify! { $State }, - stringify! { $Output }).into()) - } - } - } -} - -/// Stack things on top of each other, -#[macro_export] macro_rules! lay (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::b(bsp, $expr);)*; bsp }}); - -/// Stack southward. -#[macro_export] macro_rules! col (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::s(bsp, $expr);)*; bsp }}); - -/// Stack northward. -#[macro_export] macro_rules! col_up (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::n(bsp, $expr);)*; bsp }}); - -/// Stack eastward. -#[macro_export] macro_rules! row (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::e(bsp, $expr);)*; bsp }}); - -/// Define layout operation. -macro_rules! layout_op_xy ( - // Variant for layout ops that take no coordinates - (0: $T: ident) => { - impl $T { - #[inline] pub const fn inner (&self) -> &A { - match self { Self::X(c) | Self::Y(c) | Self::XY(c) => c } - } - } - impl> Draw for $T { - fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) } - } - }; - // Variant for layout ops that take one coordinate - (1: $T: ident) => { - impl $T { - #[inline] pub const fn inner (&self) -> &A { - match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c, } - } - } - impl> Draw for $T { - fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) } - } - impl $T { - #[inline] pub fn dx (&self) -> U { - match self { Self::X(x, _) | Self::XY(x, ..) => *x, _ => 0.into() } - } - #[inline] pub fn dy (&self) -> U { - match self { Self::Y(y, _) | Self::XY(y, ..) => *y, _ => 0.into() } - } - } - }; - (1 opt: $T: ident) => { - impl $T { - #[inline] pub const fn inner (&self) -> &A { - match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c, } - } - } - impl> Draw for $T { - fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) } - } - impl $T { - #[inline] pub const fn dx (&self) -> Option { - match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } - } - #[inline] pub const fn dy (&self) -> Option { - match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } - } - } - }; -); - -// Implement layout op that increments X and/or Y by fixed amount. -macro_rules! push_pull(($T:ident: $method: ident)=>{ - layout_op_xy!(1: $T); - impl> Layout for $T { - fn x (&self, area: O::Area) -> O::Unit { area.x().$method(self.dx()) } - fn y (&self, area: O::Area) -> O::Unit { area.y().$method(self.dy()) } - } -}); - -macro_rules! impl_map_direction (($name:ident, $axis:ident, $align:ident)=>{ - impl<'a, O, A, B, I, F> Map< - O, A, Push>>>, I, F, fn(A, usize)->B - > where - O: Out, - B: Draw, - I: Iterator + Send + Sync + 'a, - F: Fn() -> I + Send + Sync + 'a - { - pub const fn $name ( - size: O::Unit, - get_iter: F, - get_item: impl Fn(A, usize)->B + Send + Sync - ) -> Map< - O, A, - Push>>, - I, F, - impl Fn(A, usize)->Push>> + Send + Sync - > { - Map { - __: PhantomData, - get_iter, - get_item: move |item: A, index: usize|{ - // FIXME: multiply - let mut push: O::Unit = O::Unit::from(0u16); - for _ in 0..index { - push = push + size; - } - Push::$axis(push, Align::$align(Fixed::$axis(size, get_item(item, index)))) - } - } - } - } -}); diff --git a/output/src/out_structs.rs b/output/src/out_structs.rs index 69278b1..9f1d74e 100644 --- a/output/src/out_structs.rs +++ b/output/src/out_structs.rs @@ -1,23 +1,27 @@ use crate::*; /// A point (X, Y). -pub struct XY(N, N); +pub struct XY(pub C, pub C); /// A size (Width, Height). -pub struct WH(N, N); +pub struct WH(pub C, pub C); /// Point with size. /// /// TODO: anchor field (determines at which corner/side is X0 Y0) -pub struct XYWH(N, N, N, N); +pub struct XYWH(pub C, pub C, pub C, pub C); /// A cardinal direction. #[derive(Copy, Clone, PartialEq, Debug)] #[cfg_attr(test, derive(Arbitrary))] -pub enum Direction { North, South, East, West, Above, Below } +pub enum Direction { + North, South, East, West, Above, Below +} /// 9th of area to place. #[derive(Debug, Copy, Clone, Default)] -pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W } +pub enum Alignment { + #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W +} /// A widget that tracks its rendered width and height #[derive(Default)] pub struct Measure { diff --git a/output/src/out_traits.rs b/output/src/out_traits.rs index 7dea104..726fc04 100644 --- a/output/src/out_traits.rs +++ b/output/src/out_traits.rs @@ -30,9 +30,9 @@ pub trait Out: Send + Sync + Sized { /// Unit of length type Unit: Coord; /// Rectangle without offset - type Size: Size; + type Size: HasWH; /// Rectangle with offset - type Area: Area; + type Area: HasXYWH; /// Current output area fn area (&self) -> Self::Area; /// Mutable pointer to area.