1- #[ cfg( feature = "alloc" ) ]
21use alloc:: borrow;
2+ use alloc:: boxed:: Box ;
33use core:: any:: Any ;
4+ use core:: cell:: UnsafeCell ;
45use core:: fmt;
56use core:: hash;
67use core:: iter:: FusedIterator ;
78use core:: marker:: PhantomData ;
89use core:: mem:: ManuallyDrop ;
910use core:: ops:: { Deref , DerefMut } ;
11+ use core:: ptr;
1012use core:: ptr:: NonNull ;
1113
1214use objc2:: rc:: AutoreleasePool ;
13- use objc2:: rc:: WeakPtr ;
14- use objc2:: runtime:: Object ;
1515use objc2:: Message ;
1616
1717/// A type used to mark that a struct owns the object(s) it contains,
@@ -60,6 +60,9 @@ impl Ownership for Shared {}
6060/// a reference-counting pointer that, when cloned, increases the reference
6161/// count.
6262///
63+ /// [`Box`]: alloc::boxed::Box
64+ /// [`Arc`]: alloc::sync::Arc
65+ ///
6366/// # Caveats
6467///
6568/// If the inner type implements [`Drop`], that implementation will not be
@@ -179,6 +182,8 @@ impl<T: Message, O: Ownership> Id<T, O> {
179182 /// Additionally, the pointer must be valid as a reference (aligned,
180183 /// dereferencable and initialized, see the [`std::ptr`] module for more
181184 /// information).
185+ ///
186+ /// [`std::ptr`]: core::ptr
182187 //
183188 // This would be illegal:
184189 // ```no_run
@@ -456,14 +461,12 @@ impl<I: ExactSizeIterator> ExactSizeIterator for Id<I, Owned> {
456461
457462impl < I : FusedIterator > FusedIterator for Id < I , Owned > { }
458463
459- #[ cfg( feature = "alloc" ) ]
460464impl < T , O > borrow:: Borrow < T > for Id < T , O > {
461465 fn borrow ( & self ) -> & T {
462466 & * * self
463467 }
464468}
465469
466- #[ cfg( feature = "alloc" ) ]
467470impl < T > borrow:: BorrowMut < T > for Id < T , Owned > {
468471 fn borrow_mut ( & mut self ) -> & mut T {
469472 & mut * * self
@@ -502,29 +505,91 @@ pub type ShareId<T> = Id<T, Shared>;
502505
503506/// A pointer type for a weak reference to an Objective-C reference counted
504507/// object.
508+ ///
509+ /// Allows breaking reference cycles and safely checking whether the object
510+ /// has been deallocated.
511+ #[ repr( transparent) ]
505512pub struct WeakId < T > {
506- ptr : WeakPtr ,
513+ /// We give the runtime the address to this box, so that it can modify it
514+ /// even if the `WeakId` is moved.
515+ ///
516+ /// Loading may modify the pointer through a shared reference, so we use
517+ /// an UnsafeCell to get a *mut without self being mutable.
518+ inner : Box < UnsafeCell < * mut T > > ,
519+ /// TODO: Variance and dropck
507520 item : PhantomData < T > ,
508521}
509522
510523impl < T : Message > WeakId < T > {
511- /// Construct a new [`WeakId`] referencing the given [`ShareId`].
512- pub fn new ( obj : & ShareId < T > ) -> WeakId < T > {
513- // SAFETY: The pointer is valid
514- let ptr = unsafe { WeakPtr :: new ( obj. ptr . as_ptr ( ) as * mut Object ) } ;
515- WeakId {
516- ptr,
524+ /// Construct a new [`WeakId`] referencing the given shared [`Id`].
525+ #[ doc( alias = "objc_initWeak" ) ]
526+ pub fn new ( obj : & Id < T , Shared > ) -> Self {
527+ // Note that taking `&Id<T, Owned>` would not be safe since that would
528+ // allow loading an `Id<T, Shared>` later on.
529+
530+ // SAFETY: `obj` is valid
531+ unsafe { Self :: new_inner ( & * * obj as * const T as * mut T ) }
532+ }
533+
534+ /// # Safety
535+ ///
536+ /// The object must be valid or null.
537+ unsafe fn new_inner ( obj : * mut T ) -> Self {
538+ let inner = Box :: new ( UnsafeCell :: new ( ptr:: null_mut ( ) ) ) ;
539+ // SAFETY: `ptr` will never move, and the caller verifies `obj`
540+ objc2_sys:: objc_initWeak ( inner. get ( ) as _ , obj as _ ) ;
541+ Self {
542+ inner,
517543 item : PhantomData ,
518544 }
519545 }
520546
521- /// Load a [`ShareId`] from the [`WeakId `] if the object still exists.
547+ /// Load a shared (and retained) [`Id `] if the object still exists.
522548 ///
523549 /// Returns [`None`] if the object has been deallocated.
524- pub fn load ( & self ) -> Option < ShareId < T > > {
525- let obj = self . ptr . load ( ) ;
526- let ptr = * ManuallyDrop :: new ( obj) . deref ( ) . deref ( ) as * mut T ;
527- NonNull :: new ( ptr) . map ( |ptr| unsafe { Id :: new ( ptr) } )
550+ #[ doc( alias = "upgrade" ) ]
551+ #[ doc( alias = "objc_loadWeak" ) ]
552+ #[ doc( alias = "objc_loadWeakRetained" ) ]
553+ #[ inline]
554+ pub fn load ( & self ) -> Option < Id < T , Shared > > {
555+ let ptr: * mut * mut objc2_sys:: objc_object = self . inner . get ( ) as _ ;
556+ let obj = unsafe { objc2_sys:: objc_loadWeakRetained ( ptr) } as * mut T ;
557+ NonNull :: new ( obj) . map ( |obj| unsafe { Id :: new ( obj) } )
558+ }
559+ }
560+
561+ impl < T > Drop for WeakId < T > {
562+ /// Drops the `WeakId` pointer.
563+ #[ doc( alias = "objc_destroyWeak" ) ]
564+ fn drop ( & mut self ) {
565+ unsafe {
566+ objc2_sys:: objc_destroyWeak ( self . inner . get ( ) as _ ) ;
567+ }
568+ }
569+ }
570+
571+ impl < T > Clone for WeakId < T > {
572+ /// Makes a clone of the `WeakId` that points to the same object.
573+ #[ doc( alias = "objc_copyWeak" ) ]
574+ fn clone ( & self ) -> Self {
575+ let ptr = Box :: new ( UnsafeCell :: new ( ptr:: null_mut ( ) ) ) ;
576+ unsafe {
577+ objc2_sys:: objc_copyWeak ( ptr. get ( ) as _ , self . inner . get ( ) as _ ) ;
578+ }
579+ Self {
580+ inner : ptr,
581+ item : PhantomData ,
582+ }
583+ }
584+ }
585+
586+ impl < T : Message > Default for WeakId < T > {
587+ /// Constructs a new `WeakId<T>` that doesn't reference any object.
588+ ///
589+ /// Calling [`Self::load`] on the return value always gives [`None`].
590+ fn default ( ) -> Self {
591+ // SAFETY: The pointer is null
592+ unsafe { Self :: new_inner ( ptr:: null_mut ( ) ) }
528593 }
529594}
530595
@@ -534,6 +599,16 @@ unsafe impl<T: Sync + Send> Sync for WeakId<T> {}
534599/// This implementation follows the same reasoning as `Id<T, Shared>`.
535600unsafe impl < T : Sync + Send > Send for WeakId < T > { }
536601
602+ // Unsure about the Debug bound on T, see std::sync::Weak
603+ impl < T : fmt:: Debug > fmt:: Debug for WeakId < T > {
604+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
605+ write ! ( f, "(WeakId)" )
606+ }
607+ }
608+
609+ // Underneath this is just a `Box`
610+ impl < T > Unpin for WeakId < T > { }
611+
537612#[ cfg( test) ]
538613mod tests {
539614 use core:: mem:: size_of;
@@ -569,6 +644,11 @@ mod tests {
569644 size_of:: <Option <Id <TestType , Shared >>>( ) ,
570645 size_of:: <& TestType >( )
571646 ) ;
647+
648+ assert_eq ! (
649+ size_of:: <Option <WeakId <TestType >>>( ) ,
650+ size_of:: <* const ( ) >( )
651+ ) ;
572652 }
573653
574654 #[ test]
@@ -611,4 +691,11 @@ mod tests {
611691 drop ( obj) ;
612692 assert ! ( weak. load( ) . is_none( ) ) ;
613693 }
694+
695+ #[ test]
696+ fn test_weak_default ( ) {
697+ let weak: WeakId < Object > = WeakId :: default ( ) ;
698+ assert ! ( weak. load( ) . is_none( ) ) ;
699+ drop ( weak) ;
700+ }
614701}
0 commit comments