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> {}