Skip to content

Commit

Permalink
glib: Make WeakRef cheaply cloneable
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
heftig committed Mar 6, 2023
1 parent 6bdbfe0 commit 2cabe2c
Showing 1 changed file with 28 additions and 30 deletions.
58 changes: 28 additions & 30 deletions glib/src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@
// rustdoc-stripper-ignore-next
//! `IMPL` Object wrapper implementation and `Object` binding.

use std::{cmp, fmt, hash, marker::PhantomData, mem, mem::ManuallyDrop, ops, pin::Pin, ptr};
use std::{
cmp, fmt, hash,
marker::PhantomData,
mem::{self, ManuallyDrop},
ops,
pin::Pin,
ptr,
sync::Arc,
};

use crate::{
closure::TryFromClosureReturnValue,
Expand Down Expand Up @@ -3029,9 +3037,9 @@ impl<T: ObjectType> ObjectExt for T {
#[inline]
fn downgrade(&self) -> WeakRef<T> {
unsafe {
let w = WeakRef(Box::pin(mem::zeroed()), PhantomData);
let w = WeakRef(Arc::pin(WeakRefInner(mem::zeroed(), PhantomData)));
gobject_ffi::g_weak_ref_init(
mut_override(&*w.0),
mut_override(&(*w.0).0),
self.as_object_ref().to_glib_none().0,
);
w
Expand Down Expand Up @@ -3373,9 +3381,12 @@ impl<T: ObjectType> WeakRefNotify<T> {

// rustdoc-stripper-ignore-next
/// A weak reference to an object.
#[derive(Debug)]
#[derive(Debug, PartialEq, PartialOrd)]
#[doc(alias = "GWeakRef")]
pub struct WeakRef<T: ObjectType>(Pin<Box<gobject_ffi::GWeakRef>>, PhantomData<*mut T>);
pub struct WeakRef<T: ObjectType>(Pin<Arc<WeakRefInner<T>>>);

#[derive(Debug)]
struct WeakRefInner<T: ObjectType>(gobject_ffi::GWeakRef, PhantomData<*mut T>);

impl<T: ObjectType> WeakRef<T> {
// rustdoc-stripper-ignore-next
Expand All @@ -3385,11 +3396,8 @@ impl<T: ObjectType> WeakRef<T> {
#[inline]
pub fn new() -> WeakRef<T> {
unsafe {
let mut w = WeakRef(Box::pin(mem::zeroed()), PhantomData);
gobject_ffi::g_weak_ref_init(
Pin::as_mut(&mut w.0).get_unchecked_mut(),
ptr::null_mut(),
);
let w = WeakRef(Arc::pin(WeakRefInner(mem::zeroed(), PhantomData)));
gobject_ffi::g_weak_ref_init(mut_override(&(*w.0).0), ptr::null_mut());
w
}
}
Expand All @@ -3401,7 +3409,7 @@ impl<T: ObjectType> WeakRef<T> {
pub fn set(&self, obj: Option<&T>) {
unsafe {
gobject_ffi::g_weak_ref_set(
mut_override(Pin::as_ref(&self.0).get_ref()),
mut_override(&(*self.0).0),
obj.map_or(std::ptr::null_mut(), |obj| {
obj.as_object_ref().to_glib_none().0
}),
Expand All @@ -3417,7 +3425,7 @@ impl<T: ObjectType> WeakRef<T> {
#[inline]
pub fn upgrade(&self) -> Option<T> {
unsafe {
let ptr = gobject_ffi::g_weak_ref_get(mut_override(Pin::as_ref(&self.0).get_ref()));
let ptr = gobject_ffi::g_weak_ref_get(mut_override(&(*self.0).0));
if ptr.is_null() {
None
} else {
Expand All @@ -3428,29 +3436,19 @@ impl<T: ObjectType> WeakRef<T> {
}
}

impl<T: ObjectType> Drop for WeakRef<T> {
impl<T: ObjectType> Drop for WeakRefInner<T> {
#[inline]
fn drop(&mut self) {
unsafe {
gobject_ffi::g_weak_ref_clear(Pin::as_mut(&mut self.0).get_unchecked_mut());
gobject_ffi::g_weak_ref_clear(&mut self.0);
}
}
}

impl<T: ObjectType> Clone for WeakRef<T> {
#[inline]
fn clone(&self) -> Self {
unsafe {
let o = self.upgrade();

let mut c = WeakRef(Box::pin(mem::zeroed()), PhantomData);
gobject_ffi::g_weak_ref_init(
Pin::as_mut(&mut c.0).get_unchecked_mut(),
o.to_glib_none().0 as *mut gobject_ffi::GObject,
);

c
}
Self(self.0.clone())
}
}

Expand All @@ -3461,10 +3459,10 @@ impl<T: ObjectType> Default for WeakRef<T> {
}
}

unsafe impl<T: ObjectType + Sync + Sync> Sync for WeakRef<T> {}
unsafe impl<T: ObjectType + Send + Sync> Send for WeakRef<T> {}
unsafe impl<T: ObjectType + Sync + Sync> Sync for WeakRefInner<T> {}
unsafe impl<T: ObjectType + Send + Sync> Send for WeakRefInner<T> {}

impl<T: ObjectType> PartialEq for WeakRef<T> {
impl<T: ObjectType> PartialEq for WeakRefInner<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
unsafe { self.0.priv_.p == other.0.priv_.p }
Expand All @@ -3474,11 +3472,11 @@ impl<T: ObjectType> PartialEq for WeakRef<T> {
impl<T: ObjectType> PartialEq<T> for WeakRef<T> {
#[inline]
fn eq(&self, other: &T) -> bool {
unsafe { self.0.priv_.p == other.as_ptr() as *mut std::os::raw::c_void }
unsafe { (*self.0).0.priv_.p == other.as_ptr() as *mut std::os::raw::c_void }
}
}

impl<T: ObjectType> PartialOrd for WeakRef<T> {
impl<T: ObjectType> PartialOrd for WeakRefInner<T> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
unsafe { self.0.priv_.p.partial_cmp(&other.0.priv_.p) }
Expand Down

0 comments on commit 2cabe2c

Please sign in to comment.