objc2/rc/
retained.rs

1use core::fmt;
2use core::marker::PhantomData;
3use core::mem::ManuallyDrop;
4use core::ops::Deref;
5use core::panic::{RefUnwindSafe, UnwindSafe};
6use core::ptr::{self, NonNull};
7
8use super::AutoreleasePool;
9use crate::runtime::{objc_release_fast, objc_retain_fast, AnyObject, ProtocolObject};
10use crate::{ffi, ClassType, DowncastTarget, Message};
11
12/// A reference counted pointer type for Objective-C objects.
13///
14/// [`Retained`] strongly references or "retains" the given object `T`, and
15/// decrements the retain count or "releases" it again when dropped, thereby
16/// ensuring it will be deallocated at the right time.
17///
18/// The type `T` inside `Retained<T>` can be anything that implements
19/// [`Message`].
20///
21/// This can usually be gotten from one of the methods in [the framework
22/// crates], but can also be created manually with the [`msg_send!`] macro, or
23/// even more manually with the [`Retained::retain`], [`Retained::from_raw`]
24/// and [`Retained::retain_autoreleased`] methods.
25///
26/// [the framework crates]: crate::topics::about_generated
27/// [`msg_send!`]: crate::msg_send
28///
29///
30/// # Comparison to `std` types
31///
32/// `Retained<T>` is the Objective-C equivalent of [`Arc`], that is, it is a
33/// thread-safe reference-counting pointer, and allows cloning by bumping the
34/// reference count, and weak references using [`rc::Weak`].
35///
36/// Unlike `Arc`, objects can be retained directly from a `&T` using
37/// [`Message::retain`] (for `Arc` you need `&Arc<T>`).
38///
39/// Even though most Objective-C types aren't thread safe, Objective-C has no
40/// concept of [`Rc`]. Retain/release operations are always atomic.
41///
42/// [`Arc`]: alloc::sync::Arc
43/// [`rc::Weak`]: crate::rc::Weak
44/// [`Rc`]: std::rc::Rc
45///
46///
47/// # Forwarding implementations
48///
49/// Since `Retained<T>` is a smart pointer, it [`Deref`]s to `T`.
50///
51/// It also forwards the implementation of a bunch of standard library traits
52/// such as [`PartialEq`], [`AsRef`], and so on, so that it becomes possible
53/// to use e.g. `Retained<NSString>` as if it was `NSString`. Note that having
54/// `NSString` directly is not possible since Objective-C objects cannot live
55/// on the stack, but instead must reside on the heap, and as such must be
56/// accessed behind a pointer or a reference (i.e. `&NSString`).
57///
58/// Note that because of current limitations in the Rust trait system, some
59/// traits like [`Default`], [`IntoIterator`], [`FromIterator`], [`From`] and
60/// [`Into`] are not directly implementable on `NSString`; for that use-case,
61/// we instead provide the [`DefaultRetained`], [`RetainedIntoIterator`] and
62/// [`RetainedFromIterator`] traits, which make some of the the aforementioned
63/// traits implementable on `Retained`.
64///
65/// [`DefaultRetained`]: crate::rc::DefaultRetained
66/// [`RetainedIntoIterator`]: crate::rc::RetainedIntoIterator
67/// [`RetainedFromIterator`]: crate::rc::RetainedFromIterator
68///
69///
70/// # Memory layout
71///
72/// This is guaranteed to have the same size and alignment as a pointer to the
73/// object, `*const T`.
74///
75/// Additionally, it participates in the null-pointer optimization, that is,
76/// `Option<Retained<T>>` is guaranteed to have the same size as
77/// `Retained<T>`.
78///
79///
80/// # Example
81///
82/// Various usage of `Retained` on an immutable object.
83///
84/// ```
85/// # use objc2::runtime::NSObject;
86/// # #[cfg(available_in_foundation)]
87/// use objc2_foundation::{NSObject, NSString};
88/// use objc2::rc::Retained;
89/// use objc2::{ClassType, msg_send};
90/// #
91/// # objc2::extern_class!(
92/// #     #[unsafe(super(NSObject))]
93/// #     pub struct NSString;
94/// # );
95///
96/// // Use `msg_send!` to create an `Retained` with correct memory management
97/// //
98/// // SAFETY: The types are correct, and it is safe to call the `new`
99/// // selector on `NSString`.
100/// let string: Retained<NSString> = unsafe { msg_send![NSString::class(), new] };
101/// // Or:
102/// // let string = NSString::new();
103///
104/// // Methods on `NSString` is usable via `Deref`
105/// # #[cfg(available_in_foundation)]
106/// assert_eq!(string.length(), 0);
107///
108/// // Bump the reference count of the object.
109/// let another_ref: Retained<NSString> = string.clone();
110///
111/// // Convert one of the references to a reference to `NSObject` instead
112/// let obj: Retained<NSObject> = string.into_super();
113///
114/// // And use the `Debug` impl from that
115/// assert_eq!(format!("{obj:?}"), "");
116///
117/// // Finally, the `Retained`s go out of scope, the reference counts are
118/// // decreased, and the string will deallocate
119/// ```
120#[repr(transparent)]
121#[doc(alias = "id")]
122#[doc(alias = "Id")] // Previous name
123#[doc(alias = "StrongPtr")]
124#[cfg_attr(
125    feature = "unstable-coerce-pointee",
126    derive(std::marker::CoercePointee)
127)]
128// TODO: Add `ptr::Thin` bound on `T` to allow for only extern types
129pub struct Retained<T: ?Sized> {
130    /// A pointer to the contained object. The pointer is always retained.
131    ///
132    /// It is important that this is `NonNull`, since we want to dereference
133    /// it later, and be able to use the null-pointer optimization.
134    ///
135    /// Additionally, covariance is correct because we're either the unique
136    /// owner of `T`, or `T` is immutable.
137    ptr: NonNull<T>,
138    /// Necessary for dropck even though we never actually run T's destructor,
139    /// because it might have a `dealloc` that assumes that contained
140    /// references outlive the type.
141    ///
142    /// See <https://doc.rust-lang.org/nightly/nomicon/phantom-data.html>
143    item: PhantomData<T>,
144    /// Marks the type as !UnwindSafe. Later on we'll re-enable this.
145    ///
146    /// See <https://github.com/rust-lang/rust/issues/93367> for why this is
147    /// required.
148    notunwindsafe: PhantomData<&'static mut ()>,
149}
150
151/// Short type-alias to [`Retained`].
152///
153/// This is fully deprecated since `v0.6.0`, use [`Retained`] instead.
154#[deprecated(since = "0.6.0", note = "Renamed to `Retained`.")]
155pub type Id<T> = Retained<T>;
156
157impl<T: ?Sized> Retained<T> {
158    #[inline]
159    pub(crate) unsafe fn new_nonnull(ptr: NonNull<T>) -> Self {
160        Self {
161            ptr,
162            item: PhantomData,
163            notunwindsafe: PhantomData,
164        }
165    }
166}
167
168impl<T: ?Sized + Message> Retained<T> {
169    /// Construct an [`Retained`] from a pointer that already has +1 retain count.
170    ///
171    /// Returns `None` if the pointer was NULL.
172    ///
173    /// This is useful when you have a retain count that has been handed off
174    /// from somewhere else, usually Objective-C methods like `init`, `alloc`,
175    /// `new`, `copy`, or methods with the `ns_returns_retained` attribute.
176    ///
177    /// If you do not have +1 retain count, such as if your object was
178    /// retrieved from other methods than the ones noted above, use
179    /// [`Retained::retain`] instead.
180    ///
181    ///
182    /// # Safety
183    ///
184    /// You must uphold the same requirements as described in [`Retained::retain`].
185    ///
186    /// Additionally, you must ensure the given object pointer has +1 retain
187    /// count.
188    ///
189    ///
190    /// # Example
191    ///
192    /// Comparing different ways of creating a new `NSObject`.
193    ///
194    /// ```
195    /// use objc2::rc::Retained;
196    /// use objc2::runtime::NSObject;
197    /// use objc2::{msg_send, AnyThread, ClassType};
198    ///
199    /// // Manually using `msg_send!`, pointers and `Retained::from_raw`
200    /// let obj: *mut NSObject = unsafe { msg_send![NSObject::class(), alloc] };
201    /// let obj: *mut NSObject = unsafe { msg_send![obj, init] };
202    /// // SAFETY: `-[NSObject init]` returns +1 retain count
203    /// let obj: Retained<NSObject> = unsafe { Retained::from_raw(obj).unwrap() };
204    ///
205    /// // Or automatically by specifying `Retained` as the return value from
206    /// // `msg_send!` (it will do the correct conversion internally).
207    /// let obj: Retained<NSObject> = unsafe { msg_send![NSObject::alloc(), init] };
208    ///
209    /// // Or using the `NSObject::new` method
210    /// let obj = NSObject::new();
211    /// ```
212    #[inline]
213    // Note: We don't take a reference as a parameter since it would be too
214    // easy to accidentally create two aliasing mutable references.
215    pub unsafe fn from_raw(ptr: *mut T) -> Option<Self> {
216        // Should optimize down to a noop.
217        // SAFETY: Upheld by the caller
218        NonNull::new(ptr).map(|ptr| unsafe { Retained::new_nonnull(ptr) })
219    }
220
221    /// Deprecated alias for [`Retained::from_raw`], see that for details.
222    ///
223    ///
224    /// # Safety
225    ///
226    /// Same as [`Retained::from_raw`].
227    #[deprecated = "use the more descriptive name `Retained::from_raw` instead"]
228    #[inline]
229    pub unsafe fn new(ptr: *mut T) -> Option<Self> {
230        // SAFETY: Upheld by caller
231        unsafe { Self::from_raw(ptr) }
232    }
233
234    /// Consumes the `Retained`, returning a raw pointer with +1 retain count.
235    ///
236    /// After calling this function, the caller is responsible for the memory
237    /// previously managed by the `Retained`.
238    ///
239    /// This is effectively the opposite of [`Retained::from_raw`], see that for
240    /// more details on when this function is useful.
241    ///
242    ///
243    /// # Examples
244    ///
245    /// Converting an `Retained` to a pointer and back.
246    ///
247    /// ```
248    /// use objc2::rc::Retained;
249    /// use objc2::runtime::NSObject;
250    ///
251    /// let obj = NSObject::new();
252    /// let ptr = Retained::into_raw(obj);
253    /// // SAFETY: The pointer is valid, and has +1 retain count from above.
254    /// let obj = unsafe { Retained::from_raw(ptr) }.unwrap();
255    /// ```
256    #[inline]
257    pub fn into_raw(this: Self) -> *mut T {
258        ManuallyDrop::new(this).ptr.as_ptr()
259    }
260
261    /// Returns a raw pointer to the object.
262    ///
263    /// The pointer is valid for at least as long as the `Retained` is held.
264    ///
265    /// This is an associated method, and must be called as `Retained::as_ptr(obj)`.
266    #[inline]
267    pub fn as_ptr(this: &Self) -> *const T {
268        this.ptr.as_ptr()
269    }
270
271    #[inline]
272    pub(crate) fn as_nonnull_ptr(&self) -> NonNull<T> {
273        self.ptr
274    }
275
276    #[inline]
277    pub(crate) fn consume_as_ptr_option(this: Option<Self>) -> *mut T
278    where
279        T: Sized,
280    {
281        this.map(|this| Retained::into_raw(this))
282            .unwrap_or_else(ptr::null_mut)
283    }
284}
285
286// TODO: Add ?Sized bound
287impl<T: Message> Retained<T> {
288    /// Attempt to downcast the object to a class of type `U`.
289    ///
290    /// See [`AnyObject::downcast_ref`] for more details.
291    ///
292    /// # Errors
293    ///
294    /// If casting failed, this will return the object back as the [`Err`]
295    /// type. If you do not care about this, and just want an [`Option`], use
296    /// `.downcast().ok()`.
297    ///
298    /// # Example
299    ///
300    /// Cast a string to an object, and back again.
301    ///
302    /// ```
303    /// use objc2_foundation::{NSString, NSObject};
304    ///
305    /// let string = NSString::new();
306    /// // The string is an object
307    /// let obj = string.downcast::<NSObject>().unwrap();
308    /// // And it is also a string
309    /// let string = obj.downcast::<NSString>().unwrap();
310    /// ```
311    ///
312    /// Try to cast an object to a string, which will fail and return the
313    /// object in [`Err`].
314    ///
315    /// ```
316    /// use objc2_foundation::{NSString, NSObject};
317    ///
318    /// let obj = NSObject::new();
319    /// let obj = obj.downcast::<NSString>().unwrap_err();
320    /// ```
321    //
322    // NOTE: This is _not_ an associated method, since we want it to be easy
323    // to call, and it does not conflict with `AnyObject::downcast_ref`.
324    #[inline]
325    pub fn downcast<U: DowncastTarget>(self) -> Result<Retained<U>, Retained<T>>
326    where
327        Self: 'static,
328    {
329        let ptr: *const AnyObject = Self::as_ptr(&self).cast();
330        // SAFETY: All objects are valid to re-interpret as `AnyObject`, even
331        // if the object has a lifetime (which it does not in our case).
332        let obj: &AnyObject = unsafe { &*ptr };
333
334        if obj.is_kind_of_class(U::class()).as_bool() {
335            // SAFETY: Just checked that the object is a class of type `U`,
336            // and `T` is `'static`.
337            //
338            // Generic `U` like `NSArray<NSString>` are ruled out by
339            // `U: DowncastTarget`.
340            Ok(unsafe { Self::cast_unchecked::<U>(self) })
341        } else {
342            Err(self)
343        }
344    }
345
346    /// Convert the type of the given object to another.
347    ///
348    /// This is equivalent to a `cast` between two pointers.
349    ///
350    /// See [`Retained::into_super`], [`ProtocolObject::from_retained`] and
351    /// [`Retained::downcast`] for safe alternatives.
352    ///
353    /// This is common to do when you know that an object is a subclass of
354    /// a specific class (e.g. casting an instance of `NSString` to `NSObject`
355    /// is safe because `NSString` is a subclass of `NSObject`), but do not
356    /// want to pay the (very slight) performance price of dynamically
357    /// checking that precondition with a [`downcast`].
358    ///
359    /// All `'static` objects can safely be cast to [`AnyObject`], since that
360    /// assumes no specific class.
361    ///
362    /// This is an associated method, and must be called as
363    /// `Retained::cast_unchecked(obj)`.
364    ///
365    /// [`AnyObject`]: crate::runtime::AnyObject
366    /// [`ProtocolObject::from_retained`]: crate::runtime::ProtocolObject::from_retained
367    /// [`downcast`]: Self::downcast
368    ///
369    ///
370    /// # Safety
371    ///
372    /// You must ensure that the object can be reinterpreted as the given
373    /// type.
374    ///
375    /// If `T` is not `'static`, you must ensure that `U` ensures that the
376    /// data contained by `T` is kept alive for as long as `U` lives.
377    ///
378    /// Additionally, you must ensure that any safety invariants that the new
379    /// type has are upheld.
380    #[inline]
381    pub unsafe fn cast_unchecked<U: Message>(this: Self) -> Retained<U> {
382        let ptr = ManuallyDrop::new(this).ptr.cast();
383        // SAFETY: The object is forgotten, so we have +1 retain count.
384        //
385        // Caller verifies that the returned object is of the correct type.
386        unsafe { Retained::new_nonnull(ptr) }
387    }
388
389    /// Deprecated alias of [`Retained::cast_unchecked`].
390    ///
391    /// # Safety
392    ///
393    /// See [`Retained::cast_unchecked`].
394    #[inline]
395    #[deprecated = "Use `downcast`, or `cast_unchecked` instead"]
396    pub unsafe fn cast<U: Message>(this: Self) -> Retained<U> {
397        unsafe { Self::cast_unchecked(this) }
398    }
399
400    /// Retain the pointer and construct an [`Retained`] from it.
401    ///
402    /// Returns `None` if the pointer was NULL.
403    ///
404    /// This is useful when you have been given a pointer to an object from
405    /// some API, and you would like to ensure that the object stays around
406    /// while you work on it.
407    ///
408    /// For normal Objective-C methods, you may want to use
409    /// [`Retained::retain_autoreleased`] instead, as that is usually more
410    /// performant.
411    ///
412    /// See also [`Message::retain`] for a safe alternative where you already
413    /// have a reference to the object.
414    ///
415    ///
416    /// # Safety
417    ///
418    /// The pointer must be valid as a reference (aligned, dereferenceable and
419    /// initialized, see the [`std::ptr`] module for more information), or
420    /// NULL.
421    ///
422    /// You must ensure that any data that `T` may reference lives for at
423    /// least as long as `T`.
424    ///
425    /// [`std::ptr`]: core::ptr
426    #[doc(alias = "objc_retain")]
427    #[inline]
428    pub unsafe fn retain(ptr: *mut T) -> Option<Retained<T>> {
429        // SAFETY: The caller upholds that the pointer is valid
430        let res: *mut T = unsafe { objc_retain_fast(ptr.cast()) }.cast();
431        debug_assert_eq!(res, ptr, "objc_retain did not return the same pointer");
432        // SAFETY: We just retained the object, so it has +1 retain count
433        unsafe { Self::from_raw(res) }
434    }
435
436    /// Retains a previously autoreleased object pointer.
437    ///
438    /// This is useful when calling Objective-C methods that return
439    /// autoreleased objects, see [Cocoa's Memory Management Policy][mmRules].
440    ///
441    /// This has exactly the same semantics as [`Retained::retain`], except it can
442    /// sometimes avoid putting the object into the autorelease pool, possibly
443    /// yielding increased speed and reducing memory pressure.
444    ///
445    /// Note: This relies heavily on being inlined right after [`msg_send!`],
446    /// be careful to not accidentally require instructions between these.
447    ///
448    /// [mmRules]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
449    /// [`msg_send!`]: crate::msg_send
450    ///
451    ///
452    /// # Safety
453    ///
454    /// Same as [`Retained::retain`].
455    #[doc(alias = "objc_retainAutoreleasedReturnValue")]
456    #[inline]
457    pub unsafe fn retain_autoreleased(ptr: *mut T) -> Option<Retained<T>> {
458        // Add magic nop instruction to participate in the fast autorelease
459        // scheme.
460        //
461        // See `callerAcceptsOptimizedReturn` in `objc-object.h`:
462        // https://github.com/apple-oss-distributions/objc4/blob/objc4-838/runtime/objc-object.h#L1209-L1377
463        //
464        // We will unconditionally emit these instructions, even if they end
465        // up being unused (for example because we're unlucky with inlining,
466        // some other work is done between the objc_msgSend and this, or the
467        // runtime version is too old to support it).
468        //
469        // It may seem like there should be a better way to do this, but
470        // emitting raw assembly is exactly what Clang and Swift does:
471        // swiftc: https://github.com/apple/swift/blob/swift-5.5.3-RELEASE/lib/IRGen/GenObjC.cpp#L148-L173
472        // Clang: https://github.com/llvm/llvm-project/blob/889317d47b7f046cf0e68746da8f7f264582fb5b/clang/lib/CodeGen/CGObjC.cpp#L2339-L2373
473        //
474        // Note that LLVM may sometimes insert extra instructions between the
475        // assembly and the `objc_retainAutoreleasedReturnValue` call,
476        // especially when doing tail calls and it needs to clean up the
477        // function frame. Unsure how to avoid this in a performant manner?
478        // Maybe force not doing tail calls by inserting assembly to do the
479        // call manually?
480        //
481        // Resources:
482        // - https://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html
483        // - https://www.galloway.me.uk/2012/02/how-does-objc_retainautoreleasedreturnvalue-work/
484        // - https://github.com/gfx-rs/metal-rs/issues/222
485        // - https://news.ycombinator.com/item?id=29311736
486        // - https://stackoverflow.com/a/23765612
487        //
488        // SAFETY:
489        // Based on https://doc.rust-lang.org/stable/reference/inline-assembly.html#rules-for-inline-assembly
490        //
491        // We don't care about the value of the register (so it's okay to be
492        // undefined), and its value is preserved.
493        //
494        // nomem: No reads or writes to memory are performed (this `mov`
495        //   operates entirely on registers).
496        // preserves_flags: `mov` doesn't modify any flags.
497        // nostack: We don't touch the stack.
498
499        // Only worth doing on the Apple runtime.
500        // Not supported on TARGET_OS_WIN32.
501        #[cfg(target_vendor = "apple")]
502        {
503            // Supported since macOS 10.7.
504            #[cfg(target_arch = "x86_64")]
505            {
506                // x86_64 looks at the next call instruction.
507                //
508                // This is expected to be a PLT entry - if the user specifies
509                // `-Zplt=no`, a GOT entry will be created instead, and this
510                // will not work.
511            }
512
513            // Supported since macOS 10.8.
514            #[cfg(target_arch = "arm")]
515            unsafe {
516                core::arch::asm!("mov r7, r7", options(nomem, preserves_flags, nostack))
517            };
518
519            // Supported since macOS 10.10.
520            //
521            // On macOS 13.0 / iOS 16.0 / tvOS 16.0 / watchOS 9.0, the runtime
522            // instead checks the return pointer address, so we no longer need
523            // to emit these extra instructions, see this video from WWDC22:
524            // https://developer.apple.com/videos/play/wwdc2022/110363/
525            #[cfg(all(target_arch = "aarch64", not(feature = "unstable-apple-new")))]
526            unsafe {
527                // Same as `mov x29, x29`.
528                core::arch::asm!("mov fp, fp", options(nomem, preserves_flags, nostack))
529            };
530
531            // Supported since macOS 10.12.
532            #[cfg(target_arch = "x86")]
533            unsafe {
534                core::arch::asm!("mov ebp, ebp", options(nomem, preserves_flags, nostack))
535            };
536        }
537
538        // SAFETY: Same as `Retained::retain`, this is just an optimization.
539        let res: *mut T = unsafe { ffi::objc_retainAutoreleasedReturnValue(ptr.cast()) }.cast();
540
541        // Ideally, we'd be able to specify that the above call should never
542        // be tail-call optimized (become a `jmp` instruction instead of a
543        // `call`); Rust doesn't really have a way of doing this currently, so
544        // we emit a `nop` to make such tail-call optimizations less likely to
545        // occur.
546        //
547        // This is brittle! We should find a better solution!
548        #[cfg(all(target_vendor = "apple", target_arch = "x86_64"))]
549        {
550            // SAFETY: Similar to above.
551            unsafe { core::arch::asm!("nop", options(nomem, preserves_flags, nostack)) };
552            // TODO: Possibly more efficient alternative? Also consider PLT.
553            // #![feature(asm_sym)]
554            // core::arch::asm!(
555            //     "mov rdi, rax",
556            //     "call {}",
557            //     sym objc2::ffi::objc_retainAutoreleasedReturnValue,
558            //     inout("rax") obj,
559            //     clobber_abi("C-unwind"),
560            // );
561        }
562
563        debug_assert_eq!(
564            res, ptr,
565            "objc_retainAutoreleasedReturnValue did not return the same pointer"
566        );
567
568        // SAFETY: Same as `Retained::retain`.
569        unsafe { Self::from_raw(res) }
570    }
571
572    /// Autoreleases the [`Retained`], returning a pointer.
573    ///
574    /// The object is not immediately released, but will be when the innermost
575    /// / current autorelease pool is drained.
576    ///
577    /// This is useful when defining your own classes and you have some error
578    /// parameter passed as `Option<&mut *mut NSError>`, and you want to
579    /// create and autorelease an error before returning.
580    ///
581    /// This is an associated method, and must be called as
582    /// `Retained::autorelease_ptr(obj)`.
583    ///
584    /// # Safety
585    ///
586    /// This method is safe to call, but the returned pointer is only
587    /// guaranteed to be valid until the innermost autorelease pool is
588    /// drained.
589    #[doc(alias = "objc_autorelease")]
590    #[must_use = "if you don't intend to use the object any more, drop it as usual"]
591    #[inline]
592    pub fn autorelease_ptr(this: Self) -> *mut T {
593        let ptr = ManuallyDrop::new(this).ptr.as_ptr();
594        // SAFETY:
595        // - The `ptr` is guaranteed to be valid and have at least one
596        //   retain count.
597        // - Because of the ManuallyDrop, we don't call the Drop
598        //   implementation, so the object won't also be released there.
599        let res: *mut T = unsafe { ffi::objc_autorelease(ptr.cast()) }.cast();
600        debug_assert_eq!(res, ptr, "objc_autorelease did not return the same pointer");
601        res
602    }
603
604    /// Autoreleases the [`Retained`], returning a reference bound to the pool.
605    ///
606    /// The object is not immediately released, but will be when the innermost
607    /// / current autorelease pool (given as a parameter) is drained.
608    ///
609    /// This is an associated method, and must be called as
610    /// `Retained::autorelease(obj, pool)`.
611    ///
612    /// # Safety
613    ///
614    /// The given pool must represent the innermost pool, to ensure that the
615    /// reference is not moved outside the autorelease pool into which it has
616    /// been put in.
617    #[doc(alias = "objc_autorelease")]
618    #[must_use = "if you don't intend to use the object any more, drop it as usual"]
619    #[inline]
620    #[allow(clippy::needless_lifetimes)]
621    pub unsafe fn autorelease<'p>(this: Self, pool: AutoreleasePool<'p>) -> &'p T {
622        let ptr = Self::autorelease_ptr(this);
623        // SAFETY: The pointer is valid as a reference
624        unsafe { pool.ptr_as_ref(ptr) }
625    }
626
627    #[inline]
628    pub(crate) fn autorelease_return_option(this: Option<Self>) -> *mut T {
629        let ptr: *mut T = this
630            .map(|this| ManuallyDrop::new(this).ptr.as_ptr())
631            .unwrap_or_else(ptr::null_mut);
632
633        // SAFETY: Same as `autorelease_inner`, this is just an optimization.
634        let res: *mut T = unsafe { ffi::objc_autoreleaseReturnValue(ptr.cast()) }.cast();
635        debug_assert_eq!(
636            res, ptr,
637            "objc_autoreleaseReturnValue did not return the same pointer"
638        );
639        res
640    }
641
642    /// Autoreleases and prepares the [`Retained`] to be returned to Objective-C.
643    ///
644    /// The object is not immediately released, but will be when the innermost
645    /// autorelease pool is drained.
646    ///
647    /// This is useful when [defining your own methods][classbuilder] where
648    /// you will often find yourself in need of returning autoreleased objects
649    /// to properly follow [Cocoa's Memory Management Policy][mmRules].
650    ///
651    /// To that end, you could also use [`Retained::autorelease_ptr`], but
652    /// this is more efficient than a normal `autorelease`, since it makes a
653    /// best effort attempt to hand off ownership of the retain count to a
654    /// subsequent call to `objc_retainAutoreleasedReturnValue` /
655    /// [`Retained::retain_autoreleased`] in the enclosing call frame.
656    ///
657    /// This optimization relies heavily on this function being tail called,
658    /// so make sure you only call this function at the end of your method.
659    ///
660    /// [classbuilder]: crate::runtime::ClassBuilder
661    /// [mmRules]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
662    ///
663    ///
664    /// # Example
665    ///
666    /// Returning an `Retained` from a custom method (note: the
667    /// [`define_class!`] macro supports doing this for you automatically).
668    ///
669    /// ```
670    /// use objc2::{class, msg_send, sel};
671    /// use objc2::rc::Retained;
672    /// use objc2::runtime::{AnyClass, AnyObject, ClassBuilder, Sel};
673    ///
674    /// let mut builder = ClassBuilder::new(c"ExampleObject", class!(NSObject)).unwrap();
675    ///
676    /// extern "C-unwind" fn get(cls: &AnyClass, _cmd: Sel) -> *mut AnyObject {
677    ///     let obj: Retained<AnyObject> = unsafe { msg_send![cls, new] };
678    ///     Retained::autorelease_return(obj)
679    /// }
680    ///
681    /// unsafe {
682    ///     builder.add_class_method(
683    ///         sel!(get),
684    ///         get as extern "C-unwind" fn(_, _) -> _,
685    ///     );
686    /// }
687    ///
688    /// let cls = builder.register();
689    /// ```
690    ///
691    /// [`define_class!`]: crate::define_class
692    #[doc(alias = "objc_autoreleaseReturnValue")]
693    #[must_use = "if you don't intend to use the object any more, drop it as usual"]
694    #[inline]
695    pub fn autorelease_return(this: Self) -> *mut T {
696        Self::autorelease_return_option(Some(this))
697    }
698}
699
700impl<T: ClassType + 'static> Retained<T>
701where
702    T::Super: 'static,
703{
704    /// Convert the object into its superclass.
705    //
706    // NOTE: This is _not_ an associated method, since we want it to be easy
707    // to call, and it it unlikely to conflict with anything (the reference
708    // version is called `ClassType::as_super`).
709    #[inline]
710    pub fn into_super(self) -> Retained<T::Super> {
711        // SAFETY:
712        // - The casted-to type is a superclass of the type.
713        // - Both types are `'static`, so no lifetime information is lost
714        //   (this could maybe be relaxed a bit, but let's be on the safe side
715        //   for now).
716        unsafe { Self::cast_unchecked::<T::Super>(self) }
717    }
718}
719
720// TODO: Add ?Sized bound
721impl<T: Message> Clone for Retained<T> {
722    /// Retain the object, increasing its reference count.
723    ///
724    /// This is equivalent to [`Message::retain`].
725    #[doc(alias = "objc_retain")]
726    #[doc(alias = "retain")]
727    #[inline]
728    fn clone(&self) -> Self {
729        self.retain()
730    }
731}
732
733/// `#[may_dangle]` (see [this][dropck_eyepatch]) doesn't apply here since we
734/// don't run `T`'s destructor (rather, we want to discourage having `T`s with
735/// a destructor); and even if we did run the destructor, it would not be safe
736/// to add since we cannot verify that a `dealloc` method doesn't access
737/// borrowed data.
738///
739/// [dropck_eyepatch]: https://doc.rust-lang.org/nightly/nomicon/dropck.html#an-escape-hatch
740impl<T: ?Sized> Drop for Retained<T> {
741    /// Releases the retained object.
742    ///
743    /// The contained object's destructor (`Drop` impl, if it has one) is
744    /// never run - override the `dealloc` method instead (which
745    /// `define_class!` does for you).
746    #[doc(alias = "objc_release")]
747    #[doc(alias = "release")]
748    #[inline]
749    fn drop(&mut self) {
750        // We could technically run the destructor for `T` when it is mutable,
751        // but that would be confusing and inconsistent since we cannot really
752        // guarantee that it is run if the `Retained<T>` is passed to Objective-C.
753
754        // SAFETY: The `ptr` is guaranteed to be valid and have at least one
755        // retain count.
756        unsafe { objc_release_fast(self.ptr.as_ptr().cast()) };
757    }
758}
759
760impl<T: ?Sized> Deref for Retained<T> {
761    type Target = T;
762
763    /// Obtain an immutable reference to the object.
764    // Box doesn't inline, but that's because it's a compiler built-in
765    #[inline]
766    fn deref(&self) -> &T {
767        // SAFETY: The pointer's validity is verified when the type is
768        // created.
769        unsafe { self.ptr.as_ref() }
770    }
771}
772
773impl<T: ?Sized> fmt::Pointer for Retained<T> {
774    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
775        fmt::Pointer::fmt(&self.ptr.as_ptr(), f)
776    }
777}
778
779// Sadly, it is not possible to implement general conversions between
780// `Retained`, as it conflicts with the generic `impl From<T> for T`.
781//
782// impl<T: Upcast, U> From<Retained<U>> for Retained<T> {
783//     fn from(obj: &Retained<T>) -> Self {
784//         obj.as_super().retain()
785//     }
786// }
787//
788// But we _can_ do the following implementations:
789
790impl<T: ?Sized + AsRef<U>, U: Message> From<&T> for Retained<U> {
791    /// Cast the object to its superclass, and retain it.
792    #[inline]
793    fn from(obj: &T) -> Self {
794        obj.as_ref().retain()
795    }
796}
797
798// Bounded by `T: ClassType` to prevent overlapping impls
799// (`AnyObject` implements `Message`).
800impl<T: ClassType + 'static> From<Retained<T>> for Retained<AnyObject> {
801    /// Convert the object to `AnyObject`.
802    #[inline]
803    fn from(obj: Retained<T>) -> Self {
804        // SAFETY: All 'static objects can be converted to `AnyObject`.
805        unsafe { Retained::cast_unchecked(obj) }
806    }
807}
808
809impl<P: ?Sized + 'static> From<Retained<ProtocolObject<P>>> for Retained<AnyObject> {
810    /// Convert the protocol object to `AnyObject`.
811    #[inline]
812    fn from(obj: Retained<ProtocolObject<P>>) -> Self {
813        // SAFETY: All protocol objects are Objective-C objects too.
814        unsafe { Retained::cast_unchecked(obj) }
815    }
816}
817
818/// `Retained<T>` is `Send` if `T` is `Send + Sync`.
819//
820// SAFETY:
821// - `T: Send` is required because otherwise you could move the object to
822//   another thread and let `dealloc` get called there.
823// - `T: Sync` is required because otherwise you could clone `&Retained<T>`,
824//   send it to another thread, and drop the clone last, making `dealloc` get
825//   called on the other thread.
826//
827// This is the same reasoning as for `Arc`.
828// https://doc.rust-lang.org/nomicon/arc-mutex/arc-base.html#send-and-sync
829unsafe impl<T: ?Sized + Sync + Send> Send for Retained<T> {}
830
831/// `Retained<T>` is `Sync` if `T` is `Send + Sync`.
832//
833// SAFETY:
834// - `T: Sync` is required because `&Retained<T>` give access to `&T`.
835// -`T: Send` is required because otherwise you could clone `&Retained<T>`
836//   from another thread, and drop the clone last, making `dealloc` get called
837//   on the other thread.
838//
839// This is the same reasoning as for `Arc`.
840// https://doc.rust-lang.org/nomicon/arc-mutex/arc-base.html#send-and-sync
841unsafe impl<T: ?Sized + Sync + Send> Sync for Retained<T> {}
842
843// This is valid without `T: Unpin` because we don't implement any projection.
844//
845// See https://doc.rust-lang.org/1.54.0/src/alloc/boxed.rs.html#1652-1675
846// and the `Arc` implementation.
847impl<T: ?Sized> Unpin for Retained<T> {}
848
849// Same as Arc
850impl<T: ?Sized + RefUnwindSafe> RefUnwindSafe for Retained<T> {}
851
852// Same as Arc
853impl<T: ?Sized + RefUnwindSafe> UnwindSafe for Retained<T> {}
854
855#[cfg(test)]
856mod tests {
857    use core::mem::size_of;
858
859    use static_assertions::{assert_impl_all, assert_not_impl_any};
860
861    use super::*;
862    use crate::rc::{autoreleasepool, RcTestObject, ThreadTestData};
863    use crate::runtime::{AnyObject, NSObject, NSObjectProtocol};
864    use crate::{define_class, msg_send};
865
866    #[test]
867    fn auto_traits() {
868        macro_rules! helper {
869            ($name:ident) => {
870                define_class!(
871                    #[unsafe(super(NSObject))]
872                    #[name = concat!(stringify!($name), "Test")]
873                    // Make the type not thread safe by default.
874                    #[ivars = *const ()]
875                    struct $name;
876                );
877            };
878        }
879
880        helper!(Object);
881        helper!(SendObject);
882        unsafe impl Send for SendObject {}
883        helper!(SyncObject);
884        unsafe impl Sync for SyncObject {}
885        helper!(SendSyncObject);
886        unsafe impl Send for SendSyncObject {}
887        unsafe impl Sync for SendSyncObject {}
888
889        assert_impl_all!(Retained<AnyObject>: Unpin);
890        assert_not_impl_any!(Retained<AnyObject>: Send, Sync, UnwindSafe, RefUnwindSafe);
891
892        assert_not_impl_any!(Retained<Object>: Send, Sync);
893        assert_not_impl_any!(Retained<SendObject>: Send, Sync);
894        assert_not_impl_any!(Retained<SyncObject>: Send, Sync);
895        assert_impl_all!(Retained<SendSyncObject>: Send, Sync);
896    }
897
898    #[test]
899    fn test_drop() {
900        let mut expected = ThreadTestData::current();
901
902        let obj = RcTestObject::new();
903        expected.alloc += 1;
904        expected.init += 1;
905        expected.assert_current();
906
907        drop(obj);
908        expected.release += 1;
909        expected.drop += 1;
910        expected.assert_current();
911    }
912
913    #[test]
914    fn test_autorelease() {
915        let obj = RcTestObject::new();
916        let cloned = obj.clone();
917        let mut expected = ThreadTestData::current();
918
919        autoreleasepool(|pool| {
920            let _ref = unsafe { Retained::autorelease(obj, pool) };
921            expected.autorelease += 1;
922            expected.assert_current();
923            assert_eq!(cloned.retainCount(), 2);
924        });
925        expected.release += 1;
926        expected.assert_current();
927        assert_eq!(cloned.retainCount(), 1);
928
929        autoreleasepool(|pool| {
930            let _ref = unsafe { Retained::autorelease(cloned, pool) };
931            expected.autorelease += 1;
932            expected.assert_current();
933        });
934        expected.release += 1;
935        expected.drop += 1;
936        expected.assert_current();
937    }
938
939    #[test]
940    fn test_clone() {
941        let obj = RcTestObject::new();
942        assert_eq!(obj.retainCount(), 1);
943        let mut expected = ThreadTestData::current();
944
945        expected.assert_current();
946        assert_eq!(obj.retainCount(), 1);
947
948        let cloned = obj.clone();
949        expected.retain += 1;
950        expected.assert_current();
951        assert_eq!(cloned.retainCount(), 2);
952        assert_eq!(obj.retainCount(), 2);
953
954        let obj = obj.into_super().into_super();
955        let cloned_and_type_erased = obj.clone();
956        expected.retain += 1;
957        expected.assert_current();
958        let retain_count: usize = unsafe { msg_send![&cloned_and_type_erased, retainCount] };
959        assert_eq!(retain_count, 3);
960        let retain_count: usize = unsafe { msg_send![&obj, retainCount] };
961        assert_eq!(retain_count, 3);
962
963        drop(obj);
964        expected.release += 1;
965        expected.assert_current();
966        assert_eq!(cloned.retainCount(), 2);
967
968        drop(cloned_and_type_erased);
969        expected.release += 1;
970        expected.assert_current();
971        assert_eq!(cloned.retainCount(), 1);
972
973        drop(cloned);
974        expected.release += 1;
975        expected.drop += 1;
976        expected.assert_current();
977    }
978
979    #[test]
980    fn test_retain_autoreleased_works_as_retain() {
981        let obj = RcTestObject::new();
982        let mut expected = ThreadTestData::current();
983
984        let ptr = Retained::as_ptr(&obj) as *mut RcTestObject;
985        let _obj2 = unsafe { Retained::retain_autoreleased(ptr) }.unwrap();
986        expected.retain += 1;
987        expected.assert_current();
988    }
989
990    #[test]
991    fn test_cast() {
992        let obj: Retained<RcTestObject> = RcTestObject::new();
993        let expected = ThreadTestData::current();
994
995        let obj: Retained<AnyObject> = obj.into();
996        expected.assert_current();
997
998        let _obj: Retained<RcTestObject> = Retained::downcast(obj).unwrap();
999        expected.assert_current();
1000    }
1001
1002    #[repr(C)]
1003    struct MyObject<'a> {
1004        inner: NSObject,
1005        p: PhantomData<&'a str>,
1006    }
1007
1008    /// Test that `Retained<T>` is covariant over `T`.
1009    #[allow(unused)]
1010    fn assert_retained_variance<'b>(obj: Retained<MyObject<'static>>) -> Retained<MyObject<'b>> {
1011        obj
1012    }
1013
1014    #[test]
1015    fn test_size_of() {
1016        let ptr_size = size_of::<&NSObject>();
1017
1018        assert_eq!(size_of::<Retained<NSObject>>(), ptr_size);
1019        assert_eq!(size_of::<Option<Retained<NSObject>>>(), ptr_size);
1020    }
1021
1022    #[test]
1023    fn test_into() {
1024        let obj = NSObject::new();
1025        let obj: Retained<NSObject> = Into::into(obj);
1026        let _: Retained<AnyObject> = Into::into(obj);
1027
1028        let obj_ref = &*NSObject::new();
1029        let _: Retained<NSObject> = Into::into(obj_ref);
1030        let _: Retained<AnyObject> = Into::into(obj_ref);
1031
1032        let obj_retained_ref = &NSObject::new();
1033        let _: Retained<NSObject> = Into::into(obj_retained_ref);
1034        let _: Retained<AnyObject> = Into::into(obj_retained_ref);
1035
1036        let protocol_obj = ProtocolObject::<dyn NSObjectProtocol>::from_retained(NSObject::new());
1037        let _: Retained<AnyObject> = Into::into(protocol_obj);
1038    }
1039
1040    #[test]
1041    #[cfg(feature = "unstable-coerce-pointee")]
1042    fn test_coercion() {
1043        use crate::extern_protocol;
1044
1045        extern_protocol!(
1046            unsafe trait ExampleProtocol: NSObjectProtocol {}
1047        );
1048
1049        unsafe impl ExampleProtocol for RcTestObject {}
1050
1051        let obj = RcTestObject::new();
1052        let mut expected = ThreadTestData::current();
1053
1054        let obj: Retained<dyn ExampleProtocol> = obj;
1055        expected.assert_current();
1056
1057        let obj: Retained<dyn NSObjectProtocol> = obj;
1058        expected.assert_current();
1059
1060        // TODO: Allow calling methods on trait objects like this.
1061        // let _ = obj.hash();
1062
1063        drop(obj);
1064        expected.release += 1;
1065        expected.drop += 1;
1066        expected.assert_current();
1067    }
1068}