refcount ids and delete unused

This commit is contained in:
2025-08-16 19:15:21 -04:00
parent b2acbcc189
commit 368826fe05
8 changed files with 253 additions and 173 deletions

View File

@@ -1,72 +1,12 @@
use std::{
any::{Any, TypeId},
marker::PhantomData,
};
use crate::{Painter, Ui, util::Id};
use crate::{Painter, Ui, WidgetId, WidgetIdFnRet};
use std::{any::Any, marker::PhantomData};
pub trait Widget<Ctx>: Any {
fn draw(&self, painter: &mut Painter<Ctx>);
}
pub struct AnyWidget;
/// An identifier for a widget.
/// Can index a UI to get the associated widget.
///
/// W does not need to implement widget so that AnyWidget is valid;
/// Instead, add generic bounds on methods that take an ID if they need specific data.
#[repr(C)]
#[derive(Eq, Hash, PartialEq)]
pub struct WidgetId<W = AnyWidget> {
pub(super) ty: TypeId,
pub(super) id: Id,
_pd: PhantomData<W>,
}
impl<W> std::fmt::Debug for WidgetId<W> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.id.fmt(f)
}
}
// TODO: temp
impl<W> Clone for WidgetId<W> {
fn clone(&self) -> Self {
Self::new(self.id.duplicate(), self.ty)
}
}
impl<W> WidgetId<W> {
pub(super) fn new(id: Id, ty: TypeId) -> Self {
Self {
ty,
id,
_pd: PhantomData,
}
}
pub fn erase_type(self) -> WidgetId<AnyWidget> {
self.cast_type()
}
pub fn as_any(&self) -> &WidgetId<AnyWidget> {
// safety: self is repr(C) and generic only used for phantom data
unsafe { std::mem::transmute(self) }
}
fn cast_type<W2>(self) -> WidgetId<W2> {
WidgetId {
ty: self.ty,
id: self.id,
_pd: PhantomData,
}
}
}
pub struct WidgetTag;
pub struct FnTag;
pub struct IdTag;
pub trait WidgetLike<Ctx, Tag> {
type Widget: 'static;
@@ -85,63 +25,18 @@ pub trait WidgetLike<Ctx, Tag> {
}
}
// A function that returns a widget given a UI.
// Useful for defining trait functions on widgets that create a parent widget so that the children
// don't need to be IDs yet
// pub trait WidgetFn<W: Widget<Ctx>, Ctx> = FnOnce(&mut Ui<Ctx>) -> W;
// pub trait WidgetIdFn<W, Ctx> = FnOnce(&mut Ui<Ctx>) -> WidgetId<W>;
// copium for rust analyzer
/// A function that returns a widget given a UI.
/// Useful for defining trait functions on widgets that create a parent widget so that the children
/// don't need to be IDs yet
/// currently a macro for rust analyzer (doesn't support trait aliases atm)
macro_rules! WidgetFnRet {
($W:ty, $Ctx:ty) => {
impl FnOnce(&mut $crate::Ui<$Ctx>) -> $W
};
}
pub(crate) use WidgetFnRet;
macro_rules! WidgetIdFnRet {
($W:ty, $Ctx:ty) => {
impl FnOnce(&mut $crate::Ui<$Ctx>) -> $crate::WidgetId<$W>
};
($W:ty, $Ctx:ty, $($use:tt)*) => {
impl FnOnce(&mut $crate::Ui<$Ctx>) -> $crate::WidgetId<$W> + use<$($use)*>
};
}
pub(crate) use WidgetIdFnRet;
pub trait Idable<Ctx, Tag> {
type Widget: Widget<Ctx>;
fn set(self, ui: &mut Ui<Ctx>, id: &WidgetId<Self::Widget>);
fn id<'a>(
self,
id: &WidgetId<Self::Widget>,
) -> WidgetIdFnRet!(Self::Widget, Ctx, 'a, Self, Ctx, Tag)
where
Self: Sized,
{
let id = id.clone();
move |ui| {
self.set(ui, &id);
id
}
}
}
impl<W: Widget<Ctx>, Ctx> Idable<Ctx, WidgetTag> for W {
type Widget = W;
fn set(self, ui: &mut Ui<Ctx>, id: &WidgetId<Self::Widget>) {
ui.set(id, self);
}
}
impl<F: FnOnce(&mut Ui<Ctx>) -> W, W: Widget<Ctx>, Ctx> Idable<Ctx, FnTag> for F {
type Widget = W;
fn set(self, ui: &mut Ui<Ctx>, id: &WidgetId<Self::Widget>) {
let w = self(ui);
ui.set(id, w);
}
}
impl<W: Widget<Ctx>, Ctx, F: FnOnce(&mut Ui<Ctx>) -> W> WidgetLike<Ctx, FnTag> for F {
type Widget = W;
@@ -151,13 +46,6 @@ impl<W: Widget<Ctx>, Ctx, F: FnOnce(&mut Ui<Ctx>) -> W> WidgetLike<Ctx, FnTag> f
}
}
impl<W: 'static, F: FnOnce(&mut Ui<Ctx>) -> WidgetId<W>, Ctx> WidgetLike<Ctx, IdTag> for F {
type Widget = W;
fn add(self, ui: &mut Ui<Ctx>) -> WidgetId<W> {
self(ui)
}
}
impl<W: Widget<Ctx>, Ctx> WidgetLike<Ctx, WidgetTag> for W {
type Widget = W;
fn add(self, ui: &mut Ui<Ctx>) -> WidgetId<W> {
@@ -165,13 +53,6 @@ impl<W: Widget<Ctx>, Ctx> WidgetLike<Ctx, WidgetTag> for W {
}
}
impl<W: 'static, Ctx> WidgetLike<Ctx, FnTag> for WidgetId<W> {
type Widget = W;
fn add(self, _: &mut Ui<Ctx>) -> WidgetId<W> {
self
}
}
pub struct WidgetArr<const LEN: usize, Ws> {
pub arr: [WidgetId; LEN],
_pd: PhantomData<Ws>,