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 {
|
TextureHandle {
|
||||||
slot: self.push(image),
|
slot: self.push(image),
|
||||||
size,
|
size,
|
||||||
counter: RefCounter::new(),
|
counter: RefCounter::default(),
|
||||||
send: self.send.clone(),
|
send: self.send.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,29 +3,18 @@ use std::sync::{
|
|||||||
atomic::{AtomicU32, Ordering},
|
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>);
|
pub struct RefCounter(Arc<AtomicU32>);
|
||||||
|
|
||||||
impl RefCounter {
|
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 {
|
pub fn drop(&mut self) -> bool {
|
||||||
let refs = self.0.fetch_sub(1, Ordering::Release);
|
let refs = self.0.fetch_sub(1, Ordering::Release);
|
||||||
refs == 0
|
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 {
|
impl Clone for RefCounter {
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
use std::{marker::Unsize, ops::CoerceUnsized, sync::mpsc::Sender};
|
use std::{marker::Unsize, ops::CoerceUnsized, sync::mpsc::Sender};
|
||||||
|
|
||||||
use crate::{
|
use crate::{UiRsc, Widget, util::SlotId};
|
||||||
UiRsc, Widget,
|
|
||||||
util::{RefCounter, SlotId},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub type WidgetId = 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,
|
/// 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.
|
/// 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?
|
/// TODO: ergonomic clones when they get put in rust-analyzer & don't cause ICEs?
|
||||||
pub struct StrongWidget<W: ?Sized = dyn Widget> {
|
pub struct StrongWidget<W: ?Sized = dyn Widget> {
|
||||||
pub(super) id: WidgetId,
|
pub(super) id: WidgetId,
|
||||||
counter: RefCounter,
|
|
||||||
send: Sender<WidgetId>,
|
send: Sender<WidgetId>,
|
||||||
ty: *const W,
|
ty: *const W,
|
||||||
}
|
}
|
||||||
@@ -37,7 +36,6 @@ impl<W: ?Sized> StrongWidget<W> {
|
|||||||
pub(crate) fn new(id: WidgetId, send: Sender<WidgetId>) -> Self {
|
pub(crate) fn new(id: WidgetId, send: Sender<WidgetId>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
counter: RefCounter::new(),
|
|
||||||
send,
|
send,
|
||||||
ty: null_ptr(),
|
ty: null_ptr(),
|
||||||
}
|
}
|
||||||
@@ -47,10 +45,6 @@ impl<W: ?Sized> StrongWidget<W> {
|
|||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refs(&self) -> u32 {
|
|
||||||
self.counter.refs()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn weak(&self) -> WeakWidget<W> {
|
pub fn weak(&self) -> WeakWidget<W> {
|
||||||
let Self { ty, id, .. } = *self;
|
let Self { ty, id, .. } = *self;
|
||||||
WeakWidget { ty, id }
|
WeakWidget { ty, id }
|
||||||
@@ -74,10 +68,8 @@ impl<W: ?Sized> WeakWidget<W> {
|
|||||||
|
|
||||||
impl<W: ?Sized> Drop for StrongWidget<W> {
|
impl<W: ?Sized> Drop for StrongWidget<W> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if self.counter.drop() {
|
|
||||||
let _ = self.send.send(self.id);
|
let _ = self.send.send(self.id);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WidgetIdFn<Rsc, W: ?Sized = dyn Widget>: FnOnce(&mut Rsc) -> WeakWidget<W> {}
|
pub trait WidgetIdFn<Rsc, W: ?Sized = dyn Widget>: FnOnce(&mut Rsc) -> WeakWidget<W> {}
|
||||||
|
|||||||
Reference in new issue
Block a user