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}