use std::{ marker::{PhantomData, Unsize}, mem::MaybeUninit, ops::CoerceUnsized, sync::mpsc::Sender, }; use crate::{ Ui, Widget, util::{RefCounter, SlotId}, }; pub type WidgetId = SlotId; /// An identifier for a widget that can index a UI or event ctx to get it. /// This is a strong handle that does not impl Clone, and when it is dropped, /// a signal is sent to the owning UI to clean up the resources. /// /// TODO: ergonomic clones when they get put in rust-analyzer & don't cause ICEs? pub struct WidgetHandle> { pub(super) id: WidgetId, counter: RefCounter, send: Sender, ty: *const W, state: PhantomData, } /// A weak handle to a widget. /// Will not keep it alive, but can still be used for indexing like WidgetHandle. pub struct WidgetRef> { pub(super) id: WidgetId, #[allow(unused)] ty: *const W, state: PhantomData, } pub struct WidgetHandles> { pub h: WidgetHandle, pub r: WidgetRef, } impl + ?Sized + Unsize>> WidgetHandle { pub fn any(self) -> WidgetHandle> { self } } impl WidgetHandle { pub(crate) fn new(id: WidgetId, send: Sender) -> Self { Self { id, counter: RefCounter::new(), send, ty: unsafe { MaybeUninit::zeroed().assume_init() }, state: PhantomData, } } pub fn id(&self) -> WidgetId { self.id } pub fn refs(&self) -> u32 { self.counter.refs() } pub fn weak(&self) -> WidgetRef { let Self { ty, id, .. } = *self; WidgetRef { ty, id, state: PhantomData, } } pub fn handles(self) -> WidgetHandles { let r = self.weak(); WidgetHandles { h: self, r } } } impl WidgetRef { pub fn id(&self) -> WidgetId { self.id } } impl Drop for WidgetHandle { fn drop(&mut self) { if self.counter.drop() { let _ = self.send.send(self.id); } } } pub trait WidgetIdFn>: FnOnce(&mut Ui) -> WidgetHandle { } impl) -> WidgetHandle> WidgetIdFn for F { } pub trait IdLike { type Widget: Widget + ?Sized + 'static; fn id(&self) -> WidgetId; } impl + ?Sized> IdLike for &WidgetHandle { type Widget = W; fn id(&self) -> WidgetId { self.id } } impl + ?Sized> IdLike for WidgetHandle { type Widget = W; fn id(&self) -> WidgetId { self.id } } impl + ?Sized> IdLike for WidgetRef { type Widget = W; fn id(&self) -> WidgetId { self.id } } impl IdLike for WidgetId { type Widget = dyn Widget; fn id(&self) -> WidgetId { *self } } impl, U: ?Sized, State> CoerceUnsized> for WidgetHandle { } impl, U: ?Sized> CoerceUnsized> for WidgetRef { } impl Clone for WidgetRef { fn clone(&self) -> Self { *self } } impl Copy for WidgetRef {} impl PartialEq for WidgetRef { fn eq(&self, other: &Self) -> bool { self.id == other.id } } impl PartialEq for WidgetHandle { fn eq(&self, other: &Self) -> bool { self.id == other.id } } impl std::fmt::Debug for WidgetHandle { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.id.fmt(f) } }