Skip to content

Commit 470a4b7

Browse files
committed
Refactor Ownership and WeakId into their own files
1 parent 0a6e8b6 commit 470a4b7

File tree

4 files changed

+209
-187
lines changed

4 files changed

+209
-187
lines changed

objc2/src/rc/id.rs

Lines changed: 2 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,16 @@
11
use alloc::borrow;
2-
use alloc::boxed::Box;
3-
use core::cell::UnsafeCell;
42
use core::fmt;
53
use core::hash;
64
use core::iter::FusedIterator;
75
use core::marker::PhantomData;
86
use core::mem::ManuallyDrop;
97
use core::ops::{Deref, DerefMut};
10-
use core::ptr;
118
use core::ptr::NonNull;
129

1310
use super::AutoreleasePool;
11+
use super::{Owned, Ownership, Shared};
1412
use crate::Message;
1513

16-
/// A type used to mark that a struct owns the object(s) it contains,
17-
/// so it has the sole references to them.
18-
pub enum Owned {}
19-
20-
/// A type used to mark that the object(s) a struct contains are shared,
21-
/// so there may be other references to them.
22-
pub enum Shared {}
23-
24-
mod private {
25-
pub trait Sealed {}
26-
27-
impl Sealed for super::Owned {}
28-
impl Sealed for super::Shared {}
29-
}
30-
31-
/// A type that marks what type of ownership a struct has over the object(s)
32-
/// it contains; specifically, either [`Owned`] or [`Shared`].
33-
///
34-
/// This trait is sealed and not meant to be implemented outside of the this
35-
/// crate.
36-
pub trait Ownership: private::Sealed + 'static {}
37-
38-
impl Ownership for Owned {}
39-
impl Ownership for Shared {}
40-
4114
/// An pointer for Objective-C reference counted objects.
4215
///
4316
/// [`Id`] strongly references or "retains" the given object `T`, and
@@ -539,148 +512,18 @@ impl<T, O: Ownership> Unpin for Id<T, O> {}
539512
/// A convenient alias for a shared [`Id`].
540513
pub type ShareId<T> = Id<T, Shared>;
541514

542-
/// A pointer type for a weak reference to an Objective-C reference counted
543-
/// object.
544-
///
545-
/// Allows breaking reference cycles and safely checking whether the object
546-
/// has been deallocated.
547-
#[repr(transparent)]
548-
pub struct WeakId<T> {
549-
/// We give the runtime the address to this box, so that it can modify it
550-
/// even if the `WeakId` is moved.
551-
///
552-
/// Loading may modify the pointer through a shared reference, so we use
553-
/// an UnsafeCell to get a *mut without self being mutable.
554-
inner: Box<UnsafeCell<*mut T>>,
555-
/// TODO: Variance and dropck
556-
item: PhantomData<T>,
557-
}
558-
559-
impl<T: Message> WeakId<T> {
560-
/// Construct a new [`WeakId`] referencing the given shared [`Id`].
561-
#[doc(alias = "objc_initWeak")]
562-
pub fn new(obj: &Id<T, Shared>) -> Self {
563-
// Note that taking `&Id<T, Owned>` would not be safe since that would
564-
// allow loading an `Id<T, Shared>` later on.
565-
566-
// SAFETY: `obj` is valid
567-
unsafe { Self::new_inner(&**obj as *const T as *mut T) }
568-
}
569-
570-
/// # Safety
571-
///
572-
/// The object must be valid or null.
573-
unsafe fn new_inner(obj: *mut T) -> Self {
574-
let inner = Box::new(UnsafeCell::new(ptr::null_mut()));
575-
// SAFETY: `ptr` will never move, and the caller verifies `obj`
576-
objc2_sys::objc_initWeak(inner.get() as _, obj as _);
577-
Self {
578-
inner,
579-
item: PhantomData,
580-
}
581-
}
582-
583-
/// Load a shared (and retained) [`Id`] if the object still exists.
584-
///
585-
/// Returns [`None`] if the object has been deallocated.
586-
#[doc(alias = "upgrade")]
587-
#[doc(alias = "objc_loadWeak")]
588-
#[doc(alias = "objc_loadWeakRetained")]
589-
#[inline]
590-
pub fn load(&self) -> Option<Id<T, Shared>> {
591-
let ptr: *mut *mut objc2_sys::objc_object = self.inner.get() as _;
592-
let obj = unsafe { objc2_sys::objc_loadWeakRetained(ptr) } as *mut T;
593-
NonNull::new(obj).map(|obj| unsafe { Id::new(obj) })
594-
}
595-
}
596-
597-
impl<T> Drop for WeakId<T> {
598-
/// Drops the `WeakId` pointer.
599-
#[doc(alias = "objc_destroyWeak")]
600-
fn drop(&mut self) {
601-
unsafe {
602-
objc2_sys::objc_destroyWeak(self.inner.get() as _);
603-
}
604-
}
605-
}
606-
607-
impl<T> Clone for WeakId<T> {
608-
/// Makes a clone of the `WeakId` that points to the same object.
609-
#[doc(alias = "objc_copyWeak")]
610-
fn clone(&self) -> Self {
611-
let ptr = Box::new(UnsafeCell::new(ptr::null_mut()));
612-
unsafe {
613-
objc2_sys::objc_copyWeak(ptr.get() as _, self.inner.get() as _);
614-
}
615-
Self {
616-
inner: ptr,
617-
item: PhantomData,
618-
}
619-
}
620-
}
621-
622-
impl<T: Message> Default for WeakId<T> {
623-
/// Constructs a new `WeakId<T>` that doesn't reference any object.
624-
///
625-
/// Calling [`Self::load`] on the return value always gives [`None`].
626-
fn default() -> Self {
627-
// SAFETY: The pointer is null
628-
unsafe { Self::new_inner(ptr::null_mut()) }
629-
}
630-
}
631-
632-
/// This implementation follows the same reasoning as `Id<T, Shared>`.
633-
unsafe impl<T: Sync + Send> Sync for WeakId<T> {}
634-
635-
/// This implementation follows the same reasoning as `Id<T, Shared>`.
636-
unsafe impl<T: Sync + Send> Send for WeakId<T> {}
637-
638-
// Unsure about the Debug bound on T, see std::sync::Weak
639-
impl<T: fmt::Debug> fmt::Debug for WeakId<T> {
640-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
641-
write!(f, "(WeakId)")
642-
}
643-
}
644-
645-
// Underneath this is just a `Box`
646-
impl<T> Unpin for WeakId<T> {}
647-
648515
#[cfg(test)]
649516
mod tests {
650-
use core::mem::size_of;
651517
use core::ptr::NonNull;
652518

653-
use super::{Id, Owned, ShareId, Shared, WeakId};
519+
use super::{Id, Shared};
654520
use crate::runtime::Object;
655521
use crate::{class, msg_send};
656522

657523
fn retain_count(obj: &Object) -> usize {
658524
unsafe { msg_send![obj, retainCount] }
659525
}
660526

661-
pub struct TestType {
662-
_data: [u8; 0], // TODO: `UnsafeCell`?
663-
}
664-
665-
#[test]
666-
fn test_size_of() {
667-
assert_eq!(size_of::<Id<TestType, Owned>>(), size_of::<&TestType>());
668-
assert_eq!(size_of::<Id<TestType, Shared>>(), size_of::<&TestType>());
669-
assert_eq!(
670-
size_of::<Option<Id<TestType, Owned>>>(),
671-
size_of::<&TestType>()
672-
);
673-
assert_eq!(
674-
size_of::<Option<Id<TestType, Shared>>>(),
675-
size_of::<&TestType>()
676-
);
677-
678-
assert_eq!(
679-
size_of::<Option<WeakId<TestType>>>(),
680-
size_of::<*const ()>()
681-
);
682-
}
683-
684527
#[test]
685528
fn test_clone() {
686529
let cls = class!(NSObject);
@@ -701,31 +544,4 @@ mod tests {
701544
drop(obj);
702545
assert!(retain_count(&cloned) == 1);
703546
}
704-
705-
#[test]
706-
fn test_weak() {
707-
let cls = class!(NSObject);
708-
let obj: ShareId<Object> = unsafe {
709-
let obj: *mut Object = msg_send![cls, alloc];
710-
let obj: *mut Object = msg_send![obj, init];
711-
Id::new(NonNull::new_unchecked(obj))
712-
};
713-
714-
let weak = WeakId::new(&obj);
715-
let strong = weak.load().unwrap();
716-
let strong_ptr: *const Object = &*strong;
717-
let obj_ptr: *const Object = &*obj;
718-
assert!(strong_ptr == obj_ptr);
719-
drop(strong);
720-
721-
drop(obj);
722-
assert!(weak.load().is_none());
723-
}
724-
725-
#[test]
726-
fn test_weak_default() {
727-
let weak: WeakId<Object> = WeakId::default();
728-
assert!(weak.load().is_none());
729-
drop(weak);
730-
}
731547
}

objc2/src/rc/mod.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,51 @@
6060
6161
mod autorelease;
6262
mod id;
63+
mod ownership;
6364
mod strong;
6465
mod weak;
66+
mod weak_id;
6567

6668
pub use self::autorelease::{autoreleasepool, AutoreleasePool, AutoreleaseSafe};
67-
pub use self::id::{Id, Owned, Ownership, ShareId, Shared, WeakId};
69+
pub use self::id::{Id, ShareId};
70+
pub use self::ownership::{Owned, Ownership, Shared};
6871
pub use self::strong::StrongPtr;
6972
pub use self::weak::WeakPtr;
73+
pub use self::weak_id::WeakId;
7074

7175
// These tests use NSObject, which isn't present for GNUstep
7276
#[cfg(all(test, target_vendor = "apple"))]
7377
mod tests {
78+
use core::mem::size_of;
79+
7480
use super::autoreleasepool;
7581
use super::StrongPtr;
82+
use super::{Id, Owned, Shared, WeakId};
7683
use crate::runtime::Object;
7784

85+
pub struct TestType {
86+
_data: [u8; 0], // TODO: `UnsafeCell`?
87+
}
88+
89+
#[test]
90+
fn test_size_of() {
91+
assert_eq!(size_of::<Id<TestType, Owned>>(), size_of::<&TestType>());
92+
assert_eq!(size_of::<Id<TestType, Shared>>(), size_of::<&TestType>());
93+
assert_eq!(
94+
size_of::<Option<Id<TestType, Owned>>>(),
95+
size_of::<&TestType>()
96+
);
97+
assert_eq!(
98+
size_of::<Option<Id<TestType, Shared>>>(),
99+
size_of::<&TestType>()
100+
);
101+
102+
assert_eq!(
103+
size_of::<Option<WeakId<TestType>>>(),
104+
size_of::<*const ()>()
105+
);
106+
}
107+
78108
#[test]
79109
fn test_strong_clone() {
80110
fn retain_count(obj: *mut Object) -> usize {

objc2/src/rc/ownership.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// A type used to mark that a struct owns the object(s) it contains,
2+
/// so it has the sole references to them.
3+
pub enum Owned {}
4+
5+
/// A type used to mark that the object(s) a struct contains are shared,
6+
/// so there may be other references to them.
7+
pub enum Shared {}
8+
9+
mod private {
10+
pub trait Sealed {}
11+
12+
impl Sealed for super::Owned {}
13+
impl Sealed for super::Shared {}
14+
}
15+
16+
/// A type that marks what type of ownership a struct has over the object(s)
17+
/// it contains; specifically, either [`Owned`] or [`Shared`].
18+
///
19+
/// This trait is sealed and not meant to be implemented outside of the this
20+
/// crate.
21+
pub trait Ownership: private::Sealed + 'static {}
22+
23+
impl Ownership for Owned {}
24+
impl Ownership for Shared {}

0 commit comments

Comments
 (0)