Skip to content

Commit d32746b

Browse files
committed
glib: Make WeakRef cheaply cloneable
By using an `Arc` instead of a `Box`, we can make `WeakRef::clone` a cheap operation, compared to taking a global write lock for setting a `GWeakRef`. The extra space used for the refcounts should be a fine trade-off.
1 parent 6bdbfe0 commit d32746b

File tree

1 file changed

+39
-32
lines changed

1 file changed

+39
-32
lines changed

glib/src/object.rs

+39-32
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,15 @@
33
// rustdoc-stripper-ignore-next
44
//! `IMPL` Object wrapper implementation and `Object` binding.
55
6-
use std::{cmp, fmt, hash, marker::PhantomData, mem, mem::ManuallyDrop, ops, pin::Pin, ptr};
6+
use std::{
7+
cmp, fmt, hash,
8+
marker::PhantomData,
9+
mem::{self, ManuallyDrop},
10+
ops,
11+
pin::Pin,
12+
ptr,
13+
sync::Arc,
14+
};
715

816
use crate::{
917
closure::TryFromClosureReturnValue,
@@ -3029,9 +3037,12 @@ impl<T: ObjectType> ObjectExt for T {
30293037
#[inline]
30303038
fn downgrade(&self) -> WeakRef<T> {
30313039
unsafe {
3032-
let w = WeakRef(Box::pin(mem::zeroed()), PhantomData);
3040+
let w = WeakRef(Arc::pin(WeakRefInner {
3041+
ffi: mem::zeroed(),
3042+
phantom: PhantomData,
3043+
}));
30333044
gobject_ffi::g_weak_ref_init(
3034-
mut_override(&*w.0),
3045+
mut_override(&w.0.ffi),
30353046
self.as_object_ref().to_glib_none().0,
30363047
);
30373048
w
@@ -3373,9 +3384,15 @@ impl<T: ObjectType> WeakRefNotify<T> {
33733384

33743385
// rustdoc-stripper-ignore-next
33753386
/// A weak reference to an object.
3376-
#[derive(Debug)]
3387+
#[derive(Debug, PartialEq, PartialOrd)]
33773388
#[doc(alias = "GWeakRef")]
3378-
pub struct WeakRef<T: ObjectType>(Pin<Box<gobject_ffi::GWeakRef>>, PhantomData<*mut T>);
3389+
pub struct WeakRef<T: ObjectType>(Pin<Arc<WeakRefInner<T>>>);
3390+
3391+
#[derive(Debug)]
3392+
struct WeakRefInner<T: ObjectType> {
3393+
ffi: gobject_ffi::GWeakRef,
3394+
phantom: PhantomData<*mut T>,
3395+
}
33793396

33803397
impl<T: ObjectType> WeakRef<T> {
33813398
// rustdoc-stripper-ignore-next
@@ -3385,11 +3402,11 @@ impl<T: ObjectType> WeakRef<T> {
33853402
#[inline]
33863403
pub fn new() -> WeakRef<T> {
33873404
unsafe {
3388-
let mut w = WeakRef(Box::pin(mem::zeroed()), PhantomData);
3389-
gobject_ffi::g_weak_ref_init(
3390-
Pin::as_mut(&mut w.0).get_unchecked_mut(),
3391-
ptr::null_mut(),
3392-
);
3405+
let w = WeakRef(Arc::pin(WeakRefInner {
3406+
ffi: mem::zeroed(),
3407+
phantom: PhantomData,
3408+
}));
3409+
gobject_ffi::g_weak_ref_init(mut_override(&w.0.ffi), ptr::null_mut());
33933410
w
33943411
}
33953412
}
@@ -3401,7 +3418,7 @@ impl<T: ObjectType> WeakRef<T> {
34013418
pub fn set(&self, obj: Option<&T>) {
34023419
unsafe {
34033420
gobject_ffi::g_weak_ref_set(
3404-
mut_override(Pin::as_ref(&self.0).get_ref()),
3421+
mut_override(&self.0.ffi),
34053422
obj.map_or(std::ptr::null_mut(), |obj| {
34063423
obj.as_object_ref().to_glib_none().0
34073424
}),
@@ -3417,7 +3434,7 @@ impl<T: ObjectType> WeakRef<T> {
34173434
#[inline]
34183435
pub fn upgrade(&self) -> Option<T> {
34193436
unsafe {
3420-
let ptr = gobject_ffi::g_weak_ref_get(mut_override(Pin::as_ref(&self.0).get_ref()));
3437+
let ptr = gobject_ffi::g_weak_ref_get(mut_override(&self.0.ffi));
34213438
if ptr.is_null() {
34223439
None
34233440
} else {
@@ -3428,29 +3445,19 @@ impl<T: ObjectType> WeakRef<T> {
34283445
}
34293446
}
34303447

3431-
impl<T: ObjectType> Drop for WeakRef<T> {
3448+
impl<T: ObjectType> Drop for WeakRefInner<T> {
34323449
#[inline]
34333450
fn drop(&mut self) {
34343451
unsafe {
3435-
gobject_ffi::g_weak_ref_clear(Pin::as_mut(&mut self.0).get_unchecked_mut());
3452+
gobject_ffi::g_weak_ref_clear(&mut self.ffi);
34363453
}
34373454
}
34383455
}
34393456

34403457
impl<T: ObjectType> Clone for WeakRef<T> {
34413458
#[inline]
34423459
fn clone(&self) -> Self {
3443-
unsafe {
3444-
let o = self.upgrade();
3445-
3446-
let mut c = WeakRef(Box::pin(mem::zeroed()), PhantomData);
3447-
gobject_ffi::g_weak_ref_init(
3448-
Pin::as_mut(&mut c.0).get_unchecked_mut(),
3449-
o.to_glib_none().0 as *mut gobject_ffi::GObject,
3450-
);
3451-
3452-
c
3453-
}
3460+
Self(self.0.clone())
34543461
}
34553462
}
34563463

@@ -3461,27 +3468,27 @@ impl<T: ObjectType> Default for WeakRef<T> {
34613468
}
34623469
}
34633470

3464-
unsafe impl<T: ObjectType + Sync + Sync> Sync for WeakRef<T> {}
3465-
unsafe impl<T: ObjectType + Send + Sync> Send for WeakRef<T> {}
3471+
unsafe impl<T: ObjectType + Sync + Sync> Sync for WeakRefInner<T> {}
3472+
unsafe impl<T: ObjectType + Send + Sync> Send for WeakRefInner<T> {}
34663473

3467-
impl<T: ObjectType> PartialEq for WeakRef<T> {
3474+
impl<T: ObjectType> PartialEq for WeakRefInner<T> {
34683475
#[inline]
34693476
fn eq(&self, other: &Self) -> bool {
3470-
unsafe { self.0.priv_.p == other.0.priv_.p }
3477+
unsafe { self.ffi.priv_.p == other.ffi.priv_.p }
34713478
}
34723479
}
34733480

34743481
impl<T: ObjectType> PartialEq<T> for WeakRef<T> {
34753482
#[inline]
34763483
fn eq(&self, other: &T) -> bool {
3477-
unsafe { self.0.priv_.p == other.as_ptr() as *mut std::os::raw::c_void }
3484+
unsafe { self.0.ffi.priv_.p == other.as_ptr() as *mut std::os::raw::c_void }
34783485
}
34793486
}
34803487

3481-
impl<T: ObjectType> PartialOrd for WeakRef<T> {
3488+
impl<T: ObjectType> PartialOrd for WeakRefInner<T> {
34823489
#[inline]
34833490
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
3484-
unsafe { self.0.priv_.p.partial_cmp(&other.0.priv_.p) }
3491+
unsafe { self.ffi.priv_.p.partial_cmp(&other.ffi.priv_.p) }
34853492
}
34863493
}
34873494

0 commit comments

Comments
 (0)