diff --git a/src/base/mod.rs b/src/base/mod.rs index 0577fac..ed22164 100644 --- a/src/base/mod.rs +++ b/src/base/mod.rs @@ -2,7 +2,8 @@ use std::ops::Range; use crate::{ primitive::{Axis, Painter, RoundedRectData, UIRegion}, - UIColor, Widget, WidgetArrLike, WidgetFn, WidgetId, WidgetLike, + ToId, UIColor, Widget, WidgetArrLike, WidgetFn, WidgetId, WidgetIdLikeTuple, WidgetLike, + WidgetLikeTuple, }; #[derive(Clone, Copy)] @@ -134,9 +135,12 @@ pub trait WidgetArrUtil { fn span(self, axis: Axis, ratios: [impl UINum; LEN]) -> impl WidgetLike; } -impl> WidgetArrUtil for Wa { +impl> WidgetArrUtil for Wa +where + >::Wrap: WidgetIdLikeTuple, +{ fn span(self, axis: Axis, ratios: [impl UINum; LEN]) -> impl WidgetLike { - WidgetFn(move |ui| Span::proportioned(axis, ratios, self.ui(ui).arr)) + WidgetFn(move |ui| Span::proportioned(axis, ratios, self.ui(ui).erase_types())) } } diff --git a/src/layout/ui.rs b/src/layout/ui.rs index 0cb28cb..60c91c0 100644 --- a/src/layout/ui.rs +++ b/src/layout/ui.rs @@ -32,10 +32,10 @@ impl From for UIBuilder { impl UIBuilder { pub fn add(&mut self, w: W) -> WidgetRef { - WidgetRef::new(self.clone(), [self.push(w)]) + WidgetRef::new(self.clone(), (self.push(w),)) } - pub fn push(&mut self, w: W) -> WidgetId { + pub fn push(&mut self, w: W) -> WidgetId { let mut ui = self.ui.borrow_mut(); let id = ui.ids.next(); ui.widgets.insert(id.duplicate(), w); diff --git a/src/layout/widget.rs b/src/layout/widget.rs index 9700dac..4bd2e68 100644 --- a/src/layout/widget.rs +++ b/src/layout/widget.rs @@ -3,7 +3,11 @@ use std::{ marker::PhantomData, }; -use crate::{primitive::Painter, util::ID, UIBuilder}; +use crate::{ + primitive::Painter, + util::{impl_tuple, ID}, + UIBuilder, +}; pub trait Widget: 'static + Any { fn draw(&self, painter: &mut Painter); @@ -23,7 +27,7 @@ pub struct WidgetId { } // TODO: temp -impl Clone for WidgetId { +impl Clone for WidgetId { fn clone(&self) -> Self { Self { ty: self.ty, @@ -55,7 +59,7 @@ impl WidgetId { } pub trait WidgetLike { - type Widget; + type Widget: Widget; fn add(self, ui: &mut UIBuilder) -> WidgetId; } @@ -77,89 +81,98 @@ impl WidgetLike for W { } } -impl WidgetLike for WidgetId { +impl WidgetLike for WidgetId { type Widget = W; fn add(self, _: &mut UIBuilder) -> WidgetId { self } } -impl WidgetLike for WidgetArr<1, (W,)> { +impl WidgetLike for WidgetArr<1, (W,)> { type Widget = W; fn add(self, _: &mut UIBuilder) -> WidgetId { - let [id] = self.arr; - id.cast_type() + self.arr.0 } } -pub struct WidgetArr { +pub struct WidgetArr> { pub ui: UIBuilder, - pub arr: [WidgetId<()>; LEN], - _pd: PhantomData, + pub arr: Ws::Wrap, } -impl WidgetArr { - pub fn new(ui: UIBuilder, arr: [WidgetId<()>; LEN]) -> Self { - Self { - ui, - arr, - _pd: PhantomData, - } +impl> WidgetArr +where + Ws::Wrap: WidgetIdLikeTuple, +{ + pub fn new(ui: UIBuilder, arr: Ws::Wrap) -> Self { + Self { ui, arr } + } + pub fn erase_types(self) -> [WidgetId; LEN] { + self.arr.map::(&mut ()) } } pub type WidgetRef = WidgetArr<1, (W,)>; -impl WidgetRef { - pub fn handle(&self) -> WidgetId { - let [id] = &self.arr; - id.clone().cast_type() +impl WidgetRef { + pub fn handle(&self) -> WidgetId { + self.arr.0.clone() } - pub fn to_id(self) -> WidgetId { - let [id] = self.arr; - id.cast_type() + pub fn to_id(self) -> WidgetId { + self.arr.0 } } pub trait WidgetArrLike { - type Ws; + type Ws: WidgetLikeTuple; fn ui(self, ui: &mut UIBuilder) -> WidgetArr; } -impl WidgetArrLike for WidgetArr { +impl> WidgetArrLike for WidgetArr { type Ws = Ws; fn ui(self, _: &mut UIBuilder) -> WidgetArr { self } } -// I hate this language it's so bad why do I even use it -macro_rules! impl_widget_arr { - ($n:expr;$($T:tt)*) => { - impl<$($T: WidgetLike,)*> WidgetArrLike<$n> for ($($T,)*) { - type Ws = ($($T::Widget,)*); - #[allow(unused_variables)] - fn ui(self, ui: &mut UIBuilder) -> WidgetArr<$n, ($($T::Widget,)*)> { - #[allow(non_snake_case)] - let ($($T,)*) = self; - WidgetArr::new( - ui.clone(), - [$($T.add(ui).cast_type(),)*], - ) - } - } - }; +impl_tuple!(Widget); +impl_tuple!(WidgetLike); +impl_tuple!(WidgetIdLike); + +pub trait WidgetIdLike { + fn erase_type(self) -> WidgetId; } -impl_widget_arr!(1;A); -impl_widget_arr!(2;A B); -impl_widget_arr!(3;A B C); -impl_widget_arr!(4;A B C D); -impl_widget_arr!(5;A B C D E); -impl_widget_arr!(6;A B C D E F); -impl_widget_arr!(7;A B C D E F G); -impl_widget_arr!(8;A B C D E F G H); -impl_widget_arr!(9;A B C D E F G H I); -impl_widget_arr!(10;A B C D E F G H I J); -impl_widget_arr!(11;A B C D E F G H I J K); -impl_widget_arr!(12;A B C D E F G H I J K L); +impl WidgetIdLike for WidgetId { + fn erase_type(self) -> WidgetId { + self.erase_type() + } +} + +pub struct ToId; +impl WidgetLikeWrapper for ToId { + type Wrap = WidgetId; + type Ctx = UIBuilder; + fn wrap(t: T, ctx: &mut Self::Ctx) -> Self::Wrap { + t.add(ctx) + } +} + +struct EraseId; +impl WidgetIdLikeMapper for EraseId { + type Map = WidgetId<()>; + type Ctx = (); + fn map(t: Id, _: &mut Self::Ctx) -> Self::Map { + t.erase_type() + } +} + +impl, const LEN: usize> WidgetArrLike for T +where + T::Wrap: WidgetIdLikeTuple, +{ + type Ws = T; + fn ui(self, ui: &mut UIBuilder) -> WidgetArr { + WidgetArr::new(ui.clone(), self.wrap::(ui)) + } +} diff --git a/src/lib.rs b/src/lib.rs index c19b5bd..89d2b0e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,6 @@ #![feature(const_trait_impl)] #![feature(const_from)] #![feature(trait_alias)] -#![feature(generic_const_exprs)] mod layout; mod render; diff --git a/src/util/id.rs b/src/util/id.rs index ad6fc08..21edefa 100644 --- a/src/util/id.rs +++ b/src/util/id.rs @@ -27,6 +27,8 @@ impl IDTracker { id } + // TODO: use this + #[allow(dead_code)] pub fn free(&mut self, id: ID) { self.free.push(id); } diff --git a/src/util/mod.rs b/src/util/mod.rs index 3e76920..7b64d17 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,3 +1,5 @@ mod id; +mod tuple; pub use id::*; +pub use tuple::*; diff --git a/src/util/tuple.rs b/src/util/tuple.rs new file mode 100644 index 0000000..cde279f --- /dev/null +++ b/src/util/tuple.rs @@ -0,0 +1,54 @@ +macro_rules! impl_tuple { + ($Tuple:ident $Bound:ident $Wrapper:ident $Mapper:ident $n:expr;$TL:tt $($T:tt)*) => { + #[allow(non_snake_case)] + impl<$($T: $Bound,)* $TL: $Bound> $Tuple<$n> for ($($T,)* $TL,) { + type Wrap = ($(W::Wrap<$T>,)* W::Wrap<$TL>,); + type Map = [M::Map; $n]; + fn wrap(self, ctx: &mut W::Ctx) -> ($(W::Wrap<$T>,)* W::Wrap<$TL>,) { + let ($($T,)* $TL,) = self; + ($(W::wrap($T, ctx),)* W::wrap($TL, ctx),) + } + fn map(self, ctx: &mut M::Ctx) -> [M::Map; $n] { + let ($($T,)* $TL,) = self; + [$(M::map($T, ctx),)* M::map($TL, ctx)] + } + } + }; + ($Tuple:ident, $Bound:ident, $Wrapper:ident, $Mapper:ident) => { + pub trait $Wrapper { + type Wrap; + type Ctx; + fn wrap(t: T, ctx: &mut Self::Ctx) -> Self::Wrap; + } + + pub trait $Mapper { + type Map; + type Ctx; + fn map(t: T, ctx: &mut Self::Ctx) -> Self::Map; + } + + pub trait $Tuple { + type Wrap; + type Map; + fn map(self, ctx: &mut M::Ctx) -> [M::Map; LEN]; + fn wrap(self, ctx: &mut W::Ctx) -> Self::Wrap; + } + + impl_tuple!($Tuple $Bound $Wrapper $Mapper 1;A); + impl_tuple!($Tuple $Bound $Wrapper $Mapper 2;A B); + impl_tuple!($Tuple $Bound $Wrapper $Mapper 3;A B C); + impl_tuple!($Tuple $Bound $Wrapper $Mapper 4;A B C D); + impl_tuple!($Tuple $Bound $Wrapper $Mapper 5;A B C D E); + impl_tuple!($Tuple $Bound $Wrapper $Mapper 6;A B C D E F); + // impl_tuple!($Tuple $Bound $Wrapper $Mapper 7;A B C D E F G); + // impl_tuple!($Tuple $Bound $Wrapper $Mapper 8;A B C D E F G H); + // impl_tuple!($Tuple $Bound $Wrapper $Mapper 9;A B C D E F G H I); + // impl_tuple!($Tuple $Bound $Wrapper $Mapper 10;A B C D E F G H I J); + // impl_tuple!($Tuple $Bound $Wrapper $Mapper 11;A B C D E F G H I J K); + // impl_tuple!($Tuple $Bound $Wrapper $Mapper 12;A B C D E F G H I J K L); + }; + ($Bound:ident) => { + impl_tuple!(${concat($Bound, Tuple)}, $Bound, ${concat($Bound, Wrapper)}, ${concat($Bound, Mapper)}); + } +} +pub(crate) use impl_tuple;