objc2_core_foundation/
retained.rs

1use core::ffi::c_void;
2use core::fmt;
3use core::marker::PhantomData;
4use core::mem::ManuallyDrop;
5use core::ops::Deref;
6use core::panic::{RefUnwindSafe, UnwindSafe};
7use core::ptr::NonNull;
8
9use crate::{CFType, CFTypeID, ConcreteType, Type};
10
11// Symlinked to `objc2/src/rc/retained_forwarding_impls.rs`, Cargo will make
12// a copy when publishing.
13mod forwarding_impls;
14// Allow the `use super::Retained;` in `forwarding_impls` to work.
15use CFRetained as Retained;
16
17/// A reference counted pointer type for CoreFoundation types.
18///
19/// [`CFRetained`] strongly references or "retains" the given object `T`, and
20/// decrements the retain count or "releases" it again when dropped, thereby
21/// ensuring it will be deallocated at the right time.
22///
23/// The type `T` inside `CFRetained<T>` can be anything that implements
24/// [`Type`], i.e. any CoreFoundation-like type.
25///
26///
27/// # Comparison to other types
28///
29/// `CFRetained<T>` is equivalent to [`objc2::rc::Retained`], and can be
30/// converted to/from that when the `"objc2"` feature is enabled. Note though
31/// that this uses the underlying CoreFoundation primitives `CFRetain` /
32/// `CFRelease` / `CFAutorelease` instead of `objc_retain` / `objc_release` /
33/// `objc_autorelease`, to avoid depending on the Objective-C runtime if not
34/// needed.
35///
36/// You can also view `CFRetained<T>` as the CoreFoundation equivalent of
37/// [`std::sync::Arc`], that is, it is a thread-safe reference-counting smart
38/// pointer that allows cloning by bumping the reference count.
39///
40/// Unlike `Arc`, objects can be retained directly from a `&T` using
41/// [`Type::retain`] (for `Arc` you need `&Arc<T>`).
42///
43/// Weak references are not supported though without the Objective-C runtime.
44///
45#[cfg_attr(
46    not(feature = "objc2"),
47    doc = "[`objc2::rc::Retained`]: #objc2-not-available"
48)]
49///
50///
51/// # Forwarding implementations
52///
53/// Since `CFRetained<T>` is a smart pointer, it [`Deref`]s to `T`.
54///
55/// It also forwards the implementation of a bunch of standard library traits
56/// such as [`PartialEq`], [`AsRef`], and so on, so that it becomes possible
57/// to use e.g. `CFRetained<CFString>` as-if it was `CFString`. Note that
58/// having a `CFString` directly is not possible since CoreFoundation objects
59/// cannot live on the stack, but instead must reside on the heap, and as such
60/// must be accessed behind a pointer or a reference (i.e. `&CFString`).
61///
62///
63/// # Memory layout
64///
65/// This is guaranteed to have the same size and alignment as a pointer to the
66/// object, `*const T`.
67///
68/// Additionally, it participates in the null-pointer optimization, that is,
69/// `Option<CFRetained<T>>` is guaranteed to have the same size as
70/// `CFRetained<T>`.
71#[repr(transparent)]
72#[doc(alias = "id")]
73#[doc(alias = "Retained")]
74#[doc(alias = "objc2::rc::Retained")]
75#[cfg_attr(
76    feature = "unstable-coerce-pointee",
77    derive(std::marker::CoercePointee)
78)]
79// TODO: Add `ptr::Thin` bound on `T` to allow for only extern types
80pub struct CFRetained<T: ?Sized> {
81    /// A pointer to the contained type. The pointer is always retained.
82    ///
83    /// It is important that this is `NonNull`, since we want to dereference
84    /// it later, and be able to use the null-pointer optimization.
85    ptr: NonNull<T>,
86    /// Necessary for dropck even though we never actually run T's destructor,
87    /// because it might have a `dealloc` that assumes that contained
88    /// references outlive the type.
89    ///
90    /// See <https://doc.rust-lang.org/nightly/nomicon/phantom-data.html>
91    item: PhantomData<T>,
92    /// Marks the type as !UnwindSafe. Later on we'll re-enable this.
93    ///
94    /// See <https://github.com/rust-lang/rust/issues/93367> for why this is
95    /// required.
96    notunwindsafe: PhantomData<&'static mut ()>,
97}
98
99impl<T: ?Sized + Type> CFRetained<T> {
100    /// Construct a `CFRetained` from a pointer that already has +1 retain
101    /// count.
102    ///
103    /// This is useful when you have been given a pointer to a type from some
104    /// API that [returns a retained pointer][c-retain] (i.e. follows
105    /// [the Create rule]).
106    ///
107    /// [c-retain]: https://clang.llvm.org/docs/AutomaticReferenceCounting.html#auditing-of-c-retainable-pointer-interfaces
108    /// [the Create rule]: https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/uid/20001148-103029
109    ///
110    ///
111    /// # Safety
112    ///
113    /// You must uphold the same requirements as described in
114    /// [`CFRetained::retain`].
115    ///
116    /// Additionally, you must ensure the given object pointer has +1 retain
117    /// count.
118    #[inline]
119    pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
120        Self {
121            ptr,
122            item: PhantomData,
123            notunwindsafe: PhantomData,
124        }
125    }
126
127    /// Consumes the `CFRetained`, returning a raw pointer with +1 retain
128    /// count.
129    ///
130    /// After calling this function, the caller is responsible for the memory
131    /// previously managed by the `CFRetained`.
132    ///
133    /// This is effectively the opposite of [`CFRetained::from_raw`], see that
134    /// for more details on when this function is useful.
135    ///
136    /// This is an associated method, and must be called as
137    /// `CFRetained::into_raw(obj)`.
138    #[inline]
139    pub fn into_raw(this: Self) -> NonNull<T> {
140        ManuallyDrop::new(this).ptr
141    }
142
143    /// Returns a raw pointer to the type.
144    ///
145    /// The pointer is valid for at least as long as the `CFRetained` is held.
146    ///
147    /// This is an associated method, and must be called as
148    /// `CFRetained::as_ptr(&obj)`.
149    #[inline]
150    pub fn as_ptr(this: &Self) -> NonNull<T> {
151        this.ptr
152    }
153
154    /// Unchecked conversion to another CoreFoundation type.
155    ///
156    /// This is equivalent to an `unsafe` `cast` between two pointers, see
157    /// [`CFRetained::downcast`] for a safe alternative.
158    ///
159    /// This is an associated method, and must be called as
160    /// `CFRetained::cast_unchecked(obj)`.
161    ///
162    ///
163    /// # Safety
164    ///
165    /// You must ensure that the type can be reinterpreted as the given type.
166    ///
167    /// If `T` is not `'static`, you must ensure that `U` ensures that the
168    /// data contained by `T` is kept alive for as long as `U` lives.
169    ///
170    /// Additionally, you must ensure that any safety invariants that the new
171    /// type has are upheld.
172    #[inline]
173    // TODO: Add ?Sized bound
174    pub unsafe fn cast_unchecked<U: Type>(this: Self) -> CFRetained<U> {
175        let ptr = ManuallyDrop::new(this).ptr.cast();
176        // SAFETY: The type is forgotten, so we have +1 retain count.
177        //
178        // Caller verifies that the returned type is of the correct type.
179        unsafe { CFRetained::from_raw(ptr) }
180    }
181}
182
183// TODO: Add ?Sized bound
184impl<T: Type> CFRetained<T> {
185    /// Attempt to downcast the type to that of type `U`.
186    ///
187    /// This is the owned variant. Use [`CFType::downcast_ref`] if you want to
188    /// convert a reference type. See also [`ConcreteType`] for more details
189    /// on which types support being converted to.
190    ///
191    /// See [`CFType::downcast_ref`] for more details.
192    ///
193    /// [`CFType::downcast_ref`]: crate::CFType::downcast_ref
194    ///
195    /// # Errors
196    ///
197    /// If casting failed, this will return the original back as the [`Err`]
198    /// variant. If you do not care about this, and just want an [`Option`],
199    /// use `.downcast().ok()`.
200    //
201    // NOTE: This is _not_ an associated method, since we want it to be easy
202    // to call, and it does not conflict with `CFType::downcast_ref`.
203    #[doc(alias = "CFGetTypeID")]
204    pub fn downcast<U: ConcreteType>(self) -> Result<CFRetained<U>, Self>
205    where
206        T: 'static,
207    {
208        extern "C-unwind" {
209            // `*const c_void` and `Option<&CFType>` are ABI compatible.
210            #[allow(clashing_extern_declarations)]
211            fn CFGetTypeID(cf: *const c_void) -> CFTypeID;
212        }
213
214        let ptr: *const c_void = self.ptr.as_ptr().cast();
215
216        // SAFETY: The pointer is valid.
217        if unsafe { CFGetTypeID(ptr) } == U::type_id() {
218            // SAFETY: Just checked that the object is a class of type `U`,
219            // and `T` is `'static`. Additionally, `ConcreteType::type_id` is
220            // guaranteed to uniquely identify the class (including ruling out
221            // mutable subclasses), so we know for _sure_ that the class is
222            // actually of that type here.
223            Ok(unsafe { Self::cast_unchecked::<U>(self) })
224        } else {
225            Err(self)
226        }
227    }
228
229    /// Retain the pointer and construct a [`CFRetained`] from it.
230    ///
231    /// This is useful when you have been given a pointer to a type from some
232    /// API that [returns a non-retained reference][c-retain] (i.e. follows
233    /// [the Get rule]).
234    ///
235    /// See also [`Type::retain`] for a safe alternative when you already have
236    /// a reference to the type.
237    ///
238    /// [c-retain]: https://clang.llvm.org/docs/AutomaticReferenceCounting.html#auditing-of-c-retainable-pointer-interfaces
239    /// [the Get rule]: https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/uid/20001148-SW1
240    ///
241    ///
242    /// # Safety
243    ///
244    /// The pointer must be valid as a reference (aligned, dereferenceable and
245    /// initialized, see the [`std::ptr`] module for more information).
246    ///
247    /// You must ensure that if `T` is non-`'static` (i.e. has a lifetime
248    /// parameter), that any data that `T` may reference lives for at least as
249    /// long as the return value.
250    ///
251    /// [`std::ptr`]: core::ptr
252    #[doc(alias = "CFRetain")]
253    #[inline]
254    pub unsafe fn retain(ptr: NonNull<T>) -> Self {
255        extern "C-unwind" {
256            fn CFRetain(cf: *mut c_void) -> *mut c_void;
257        }
258
259        // SAFETY: The caller upholds that the pointer is valid.
260        //
261        // Note that `CFRetain` will abort if given a NULL pointer, but we
262        // avoid that here by ensuring that the pointer is non-NULL.
263        let res: *mut T = unsafe { CFRetain(ptr.as_ptr().cast()) }.cast();
264
265        // SAFETY: The pointer returned from `CFRetain` is the same as the one
266        // given, and we gave it a non-NULL pointer.
267        let res = unsafe { NonNull::new_unchecked(res) };
268
269        // SAFETY: We just retained the type, so it has +1 retain count.
270        //
271        // The pointer returned from `CFRetain` is the same as the one given,
272        // and the validity of it is upheld by the caller.
273        unsafe { Self::from_raw(res) }
274    }
275
276    /// Autoreleases the `CFRetained`, returning a pointer.
277    ///
278    /// The object is not immediately released, but will be when the innermost
279    /// / current autorelease pool is drained.
280    ///
281    /// This is an associated method, and must be called as
282    /// `CFRetained::autorelease_ptr(obj)`.
283    ///
284    /// # Safety
285    ///
286    /// This method is safe to call, but the returned pointer is only
287    /// guaranteed to be valid until the innermost autorelease pool is
288    /// drained.
289    #[doc(alias = "CFAutorelease")]
290    #[must_use = "if you don't intend to use the object any more, drop it as usual instead"]
291    #[inline]
292    pub fn autorelease_ptr(this: Self) -> *mut T {
293        extern "C-unwind" {
294            fn CFAutorelease(cf: *mut c_void) -> *mut c_void;
295        }
296
297        let ptr = Self::into_raw(this);
298        // SAFETY: The `ptr` is valid and has +1 retain count.
299        unsafe { CFAutorelease(ptr.as_ptr().cast()) }.cast()
300    }
301}
302
303// TODO: Add ?Sized bound
304impl<T: Type> Clone for CFRetained<T> {
305    /// Retain the type, increasing its reference count.
306    ///
307    /// This calls [`Type::retain`] internally.
308    #[doc(alias = "CFRetain")]
309    #[doc(alias = "retain")]
310    #[inline]
311    fn clone(&self) -> Self {
312        self.retain()
313    }
314}
315
316// Same as `objc::rc::Retained`, `#[may_dangle]` does not apply here.
317impl<T: ?Sized> Drop for CFRetained<T> {
318    /// Releases the contained type.
319    #[doc(alias = "CFRelease")]
320    #[doc(alias = "release")]
321    #[inline]
322    fn drop(&mut self) {
323        extern "C-unwind" {
324            fn CFRelease(cf: *mut c_void);
325        }
326
327        // SAFETY: The `ptr` is guaranteed to be valid, and have at least one
328        // retain count.
329        //
330        // Note that `CFRelease` will abort if given a NULL pointer, but we
331        // avoid that here by ensuring that the pointer is non-NULL.
332        unsafe { CFRelease(self.ptr.as_ptr().cast()) };
333    }
334}
335
336impl<T: ?Sized> Deref for CFRetained<T> {
337    type Target = T;
338
339    /// Obtain a reference to the type.
340    // Box doesn't inline, but that's because it's a compiler built-in
341    #[inline]
342    fn deref(&self) -> &T {
343        // SAFETY: The pointer's validity is verified when the type is
344        // created.
345        unsafe { self.ptr.as_ref() }
346    }
347}
348
349impl<T: ?Sized> fmt::Pointer for CFRetained<T> {
350    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351        fmt::Pointer::fmt(&self.ptr.as_ptr(), f)
352    }
353}
354
355// Same as what's implemented for `objc2::rc::Retained`.
356impl<T: ?Sized + AsRef<U>, U: Type> From<&T> for CFRetained<U> {
357    /// Cast the type to a superclass or `CFType`, and retain it.
358    #[inline]
359    fn from(obj: &T) -> Self {
360        obj.as_ref().retain()
361    }
362}
363
364// Use `ConcreteType` to avoid the reflexive impl (as CFType does not implement that).
365impl<T: ?Sized + ConcreteType + 'static> From<CFRetained<T>> for CFRetained<CFType> {
366    /// Convert to [`CFType`].
367    #[inline]
368    fn from(obj: CFRetained<T>) -> Self {
369        // SAFETY: All `'static` types can be converted to `CFType` without
370        // loss of information.
371        unsafe { CFRetained::cast_unchecked(obj) }
372    }
373}
374
375#[cfg(feature = "objc2")]
376impl<T: ?Sized + Type + objc2::Message> From<objc2::rc::Retained<T>> for CFRetained<T> {
377    /// Convert a [`objc2::rc::Retained`] into a [`CFRetained`].
378    ///
379    /// This only works if the type is a CoreFoundation type (implements the
380    /// [`Type`] trait).
381    ///
382    /// This conversion is cost-free.
383    #[inline]
384    fn from(obj: objc2::rc::Retained<T>) -> Self {
385        let ptr = objc2::rc::Retained::into_raw(obj);
386        let ptr = NonNull::new(ptr).unwrap();
387        // SAFETY: `T` is bound by `Type`, so we know that the type is a
388        // CoreFoundation-like type, and hence we know that it will respond to
389        // `CFRetain`/`CFRelease`.
390        //
391        // Additionally, the pointer is valid and has +1 retain count, since
392        // we're passing it from `Retained::into_raw`.
393        unsafe { Self::from_raw(ptr) }
394    }
395}
396
397#[cfg(feature = "objc2")]
398impl<T: ?Sized + objc2::Message> From<CFRetained<T>> for objc2::rc::Retained<T> {
399    /// Convert a [`CFRetained`] into a [`objc2::rc::Retained`].
400    ///
401    /// This conversion is cost-free, since CoreFoundation types are fully
402    /// interoperable with Objective-C retain/release message sending.
403    #[inline]
404    fn from(obj: CFRetained<T>) -> Self {
405        let ptr = ManuallyDrop::new(obj).ptr;
406        // SAFETY: `T` is bound by `Message`, so we know that the type is an
407        // Objective-C object, and hence we know that it will respond to
408        // `objc_retain`, `objc_release` etc.
409        //
410        // Additionally, the pointer is valid and has +1 retain count, since
411        // we're passing it from `CFRetained::into_raw`.
412        unsafe { Self::from_raw(ptr.as_ptr()) }.unwrap()
413    }
414}
415
416/// `CFRetained<T>` is `Send` if `T` is `Send + Sync`.
417//
418// SAFETY: CFRetain/CFRelease is thread safe, rest is the same as
419// `std::sync::Arc` and `objc2::rc::Retained`.
420unsafe impl<T: ?Sized + Sync + Send> Send for CFRetained<T> {}
421
422/// `CFRetained<T>` is `Sync` if `T` is `Send + Sync`.
423//
424// SAFETY: CFRetain/CFRelease is thread safe, rest is the same as
425// `std::sync::Arc` and `objc2::rc::Retained`.
426unsafe impl<T: ?Sized + Sync + Send> Sync for CFRetained<T> {}
427
428// Same as `std::sync::Arc` and `objc2::rc::Retained`.
429impl<T: ?Sized> Unpin for CFRetained<T> {}
430
431// Same as `std::sync::Arc` and `objc2::rc::Retained`.
432impl<T: ?Sized + RefUnwindSafe> RefUnwindSafe for CFRetained<T> {}
433
434// Same as `std::sync::Arc` and `objc2::rc::Retained`.
435impl<T: ?Sized + RefUnwindSafe> UnwindSafe for CFRetained<T> {}