Drop the refcount a widget handle can never raise
StrongWidget has no Clone on purpose, so the RefCounter in it never counted anything: the count stayed at zero, RefCounter::drop always answered true, and StrongWidget::refs had no caller -- while every widget made paid a heap allocation for an Arc<AtomicU32> and every one created or dropped paid two atomic read-modify-writes. The handle is the id, the sender and the type now, and Drop sends. It is 32 bytes rather than 40, and 40 rather than 48 for a dyn one. RefCounter stays for TextureHandle, which does clone -- several widgets showing one picture share its slot -- and is trimmed to what that needs: quiet_clone and refs had no callers at all, and new was Default spelt out. Bryan asked for this in #19 rather than in the review of the code written before the gate, where the fourteenth sweep had left it.
This commit is contained in:
1 parent
97fca76108
commit
429a4f1330
3 files changed
+10
-29
No files matched your search
@@ -66,7 +66,7 @@ impl Textures {
|
||||
TextureHandle {
|
||||
slot: self.push(image),
|
||||
size,
|
||||
counter: RefCounter::new(),
|
||||
counter: RefCounter::default(),
|
||||
send: self.send.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,29 +3,18 @@ use std::sync::{
|
||||
atomic::{AtomicU32, Ordering},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
/// How many handles to one thing there are, less one: a fresh counter is a
|
||||
/// single handle, which is what the derived default gives. Only
|
||||
/// [`crate::TextureHandle`] has any, a texture slot being shared by every
|
||||
/// widget drawing that picture.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct RefCounter(Arc<AtomicU32>);
|
||||
|
||||
impl RefCounter {
|
||||
pub fn new() -> Self {
|
||||
Self(Arc::new(0.into()))
|
||||
}
|
||||
pub fn refs(&self) -> u32 {
|
||||
self.0.load(Ordering::Acquire)
|
||||
}
|
||||
pub fn drop(&mut self) -> bool {
|
||||
let refs = self.0.fetch_sub(1, Ordering::Release);
|
||||
refs == 0
|
||||
}
|
||||
pub fn quiet_clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RefCounter {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for RefCounter {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use std::{marker::Unsize, ops::CoerceUnsized, sync::mpsc::Sender};
|
||||
|
||||
use crate::{
|
||||
UiRsc, Widget,
|
||||
util::{RefCounter, SlotId},
|
||||
};
|
||||
use crate::{UiRsc, Widget, util::SlotId};
|
||||
|
||||
pub type WidgetId = SlotId;
|
||||
|
||||
@@ -11,10 +8,12 @@ pub type WidgetId = SlotId;
|
||||
/// 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.
|
||||
///
|
||||
/// There is nothing to count: not being `Clone` is what makes one handle the
|
||||
/// only one, so the drop is the last one and the widget is one container's.
|
||||
///
|
||||
/// TODO: ergonomic clones when they get put in rust-analyzer & don't cause ICEs?
|
||||
pub struct StrongWidget<W: ?Sized = dyn Widget> {
|
||||
pub(super) id: WidgetId,
|
||||
counter: RefCounter,
|
||||
send: Sender<WidgetId>,
|
||||
ty: *const W,
|
||||
}
|
||||
@@ -37,7 +36,6 @@ impl<W: ?Sized> StrongWidget<W> {
|
||||
pub(crate) fn new(id: WidgetId, send: Sender<WidgetId>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
counter: RefCounter::new(),
|
||||
send,
|
||||
ty: null_ptr(),
|
||||
}
|
||||
@@ -47,10 +45,6 @@ impl<W: ?Sized> StrongWidget<W> {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn refs(&self) -> u32 {
|
||||
self.counter.refs()
|
||||
}
|
||||
|
||||
pub fn weak(&self) -> WeakWidget<W> {
|
||||
let Self { ty, id, .. } = *self;
|
||||
WeakWidget { ty, id }
|
||||
@@ -74,10 +68,8 @@ impl<W: ?Sized> WeakWidget<W> {
|
||||
|
||||
impl<W: ?Sized> Drop for StrongWidget<W> {
|
||||
fn drop(&mut self) {
|
||||
if self.counter.drop() {
|
||||
let _ = self.send.send(self.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait WidgetIdFn<Rsc, W: ?Sized = dyn Widget>: FnOnce(&mut Rsc) -> WeakWidget<W> {}
|
||||
|
||||
Reference in new issue
Block a user