objc2/top_level_traits.rs
1use alloc::ffi::CString;
2use core::ptr::NonNull;
3
4use crate::__macro_helpers::defined_ivars::get_initialized_ivar_ptr;
5use crate::encode::RefEncode;
6use crate::rc::{Allocated, Retained};
7use crate::runtime::{AnyClass, AnyProtocol, ProtocolObject};
8use crate::MainThreadMarker;
9
10/// Types that can be sent Objective-C messages.
11///
12/// Implementing this provides [`MessageReceiver`] implementations for common
13/// pointer types and references to the type, which allows using them as the
14/// receiver (first argument) in the [`msg_send!`][`crate::msg_send`] macro.
15///
16/// This trait also allows the object to be used in [`Retained`].
17///
18/// This is a subtrait of [`RefEncode`], meaning the type must also implement
19/// that, almost always with [`RefEncode::ENCODING_REF`] being
20/// [`Encoding::Object`].
21///
22/// This can be implemented for unsized (`!Sized`) types, but the intention is
23/// not to support dynamically sized types like slices, only `extern type`s
24/// (which is currently unstable).
25///
26/// [`MessageReceiver`]: crate::runtime::MessageReceiver
27/// [`Encoding::Object`]: crate::Encoding::Object
28///
29///
30/// # `Drop` interaction
31///
32/// If the inner type implements [`Drop`], that implementation will very
33/// likely not be called, since there is no way to ensure that the Objective-C
34/// runtime will do so. If you need to run some code when the object is
35/// destroyed, implement the `dealloc` method instead.
36///
37/// The [`define_class!`] macro does this for you, but the [`extern_class!`]
38/// macro fundamentally cannot.
39///
40/// [`define_class!`]: crate::define_class
41/// [`extern_class!`]: crate::extern_class
42///
43///
44/// # Safety
45///
46/// The type must represent an Objective-C object, meaning it:
47/// - Must be valid to reinterpret as [`AnyObject`].
48/// - Must be able to be the receiver of an Objective-C message sent with
49/// [`objc_msgSend`] or similar.
50/// - Must respond to the standard memory management `retain`, `release` and
51/// `autorelease` messages.
52/// - Must support weak references. (In the future we should probably make a
53/// new trait for this, for example `NSTextView` only supports weak
54/// references on macOS 10.12 or above).
55///
56/// [`AnyObject`]: crate::runtime::AnyObject
57/// [`objc_msgSend`]: https://developer.apple.com/documentation/objectivec/1456712-objc_msgsend
58///
59///
60/// # Example
61///
62/// ```
63/// use objc2::runtime::NSObject;
64/// use objc2::{Encoding, Message, RefEncode};
65///
66/// #[repr(C)]
67/// struct MyObject {
68/// // This has the exact same layout as `NSObject`
69/// inner: NSObject
70/// }
71///
72/// unsafe impl RefEncode for MyObject {
73/// const ENCODING_REF: Encoding = Encoding::Object;
74/// }
75///
76/// unsafe impl Message for MyObject {}
77///
78/// // `*mut MyObject` and other pointer/reference types to the object can
79/// // now be used in `msg_send!`
80/// //
81/// // And `Retained<MyObject>` can now be constructed.
82/// ```
83///
84/// Implement the trait manually for a class with a lifetime parameter.
85///
86/// ```
87#[doc = include_str!("../examples/class_with_lifetime.rs")]
88/// ```
89pub unsafe trait Message: RefEncode {
90 /// Increment the reference count of the receiver.
91 ///
92 /// This extends the duration in which the receiver is alive by detaching
93 /// it from the lifetime information carried by the reference.
94 ///
95 /// This is similar to using [`Clone` on `Retained<Self>`][clone-id], with
96 /// the addition that it can be used on a plain reference.
97 ///
98 /// If your type may have come from a mutable type like `NSMutableString`,
99 /// you should consider using `NSCopying::copy` instead to avoid carrying
100 /// around a mutable string when you did not intend to.
101 ///
102 /// [clone-id]: crate::rc::Retained#impl-Clone-for-Retained<T>
103 #[inline]
104 #[doc(alias = "objc_retain")]
105 fn retain(&self) -> Retained<Self>
106 where
107 Self: Sized, // Temporary
108 {
109 let ptr: *const Self = self;
110 let ptr: *mut Self = ptr as _;
111 // SAFETY:
112 // - The pointer is valid since it came from `&self`.
113 // - The lifetime of the pointer itself is extended, but any lifetime
114 // that the object may carry is still kept within the type itself.
115 let obj = unsafe { Retained::retain(ptr) };
116 // SAFETY: The pointer came from `&self`, which is always non-null,
117 // and objc_retain always returns the same value.
118 unsafe { obj.unwrap_unchecked() }
119 }
120}
121
122/// Marks types that represent specific classes.
123///
124/// Sometimes it is enough to generically know that a type is messageable,
125/// e.g. [`Retained`] works with any type that implements the [`Message`]
126/// trait. But often, you have an object that you know represents a specific
127/// Objective-C class - this trait allows you to communicate that, as well as
128/// a few properties of the class to the rest of the type-system.
129///
130/// This is implemented for your type by the
131/// [`define_class!`][crate::define_class] and
132/// [`extern_class!`][crate::extern_class] macros.
133///
134///
135/// # Safety
136///
137/// This is meant to be a sealed trait, and should not be implemented outside
138/// of the aforementioned macros. See those for safety preconditions.
139///
140///
141/// # Examples
142///
143/// Use the trait to access the [`AnyClass`] of an object.
144///
145/// ```
146/// use objc2::{ClassType, msg_send};
147/// use objc2::rc::Retained;
148/// # use objc2::runtime::{NSObject as MyObject};
149///
150/// // Get the class of the object.
151/// let cls = <MyObject as ClassType>::class();
152/// // Or, since the trait is in scope.
153/// let cls = MyObject::class();
154///
155/// // We can now access properties of the class.
156/// assert_eq!(cls.name().to_str().unwrap(), MyObject::NAME);
157///
158/// // And we can send messages to the class.
159/// //
160/// // SAFETY:
161/// // - The class is `MyObject`, which can safely be initialized with `new`.
162/// // - The return type is correctly specified.
163/// let obj: Retained<MyObject> = unsafe { msg_send![cls, new] };
164/// ```
165///
166/// Use the trait to allocate a new instance of an object.
167///
168/// ```
169/// use objc2::{msg_send, AllocAnyThread};
170/// use objc2::rc::Retained;
171/// # use objc2::runtime::{NSObject as MyObject};
172///
173/// let obj = MyObject::alloc();
174///
175/// // Now we can call initializers on this newly allocated object.
176/// //
177/// // SAFETY: `MyObject` can safely be initialized with `init`.
178/// let obj: Retained<MyObject> = unsafe { msg_send![obj, init] };
179/// ```
180///
181/// Use the [`extern_class!`][crate::extern_class] macro to implement this
182/// trait for a type.
183///
184/// ```
185/// use objc2::runtime::NSObject;
186/// use objc2::{extern_class, ClassType, AllocAnyThread};
187///
188/// extern_class!(
189/// // SAFETY: The superclass is correctly specified, and the class can be
190/// // safely used from any thread.
191/// #[unsafe(super(NSObject))]
192/// # // For testing purposes
193/// # #[name = "NSObject"]
194/// struct MyClass;
195/// );
196///
197/// let cls = MyClass::class();
198/// let obj = MyClass::alloc();
199/// ```
200//
201// Actual safety preconditions:
202//
203// 1. The type must represent a specific class.
204// 2. [`Self::Super`] must be a superclass of the class (or something that
205// represents any object, like [`AnyObject`][crate::runtime::AnyObject]).
206// 3. [`Self::ThreadKind`] must be correct. It is safe to default to the
207// super class' thread kind, `<Self::Super as ClassType>::ThreadKind`.
208// 4. [`Self::NAME`] must be the name of the class that this type represents.
209// 5. The class returned by [`Self::class`] must be the class that this type
210// represents.
211pub unsafe trait ClassType: Message {
212 /// The superclass of this class.
213 ///
214 /// If you have implemented [`Deref`] for your type, it is highly
215 /// recommended that this is equal to [`Deref::Target`].
216 ///
217 /// This may be [`AnyObject`] if the class is a root class.
218 ///
219 /// [`Deref`]: std::ops::Deref
220 /// [`Deref::Target`]: std::ops::Deref::Target
221 /// [`AnyObject`]: crate::runtime::AnyObject
222 type Super: Message;
223
224 /// Whether the type can be used from any thread, or from only the main
225 /// thread.
226 ///
227 /// One of [`dyn AllocAnyThread`] or [`dyn MainThreadOnly`].
228 ///
229 /// Setting this makes `ClassType` provide an implementation of either
230 /// [`AllocAnyThread`] or [`MainThreadOnly`].
231 ///
232 /// [`dyn AllocAnyThread`]: AllocAnyThread
233 /// [`dyn MainThreadOnly`]: MainThreadOnly
234 type ThreadKind: ?Sized + ThreadKind;
235
236 /// The name of the Objective-C class that this type represents.
237 ///
238 /// `T::NAME` is the `const` version of `T::class().name()`.
239 ///
240 /// This must not contain any NUL bytes.
241 //
242 // TODO: Convert this to CStr next time we do big changes to ClassType.
243 const NAME: &'static str;
244
245 /// Get a reference to the Objective-C class that this type represents.
246 ///
247 /// May register the class with the runtime if it wasn't already.
248 ///
249 ///
250 /// # Panics
251 ///
252 /// This may panic if something went wrong with getting or creating the
253 /// class, e.g. if the program is not properly linked to the framework
254 /// that defines the class.
255 fn class() -> &'static AnyClass;
256
257 /// Get an immutable reference to the superclass.
258 // Note: It'd be safe to provide a default impl using transmute here if
259 // we wanted to!
260 fn as_super(&self) -> &Self::Super;
261
262 #[doc(hidden)]
263 const __INNER: ();
264
265 /// Inner type to use when subclassing with `define_class!`.
266 ///
267 /// This is used by NSObject to control which auto traits are set for
268 /// defined subclasses. Set to `= Self` in all other cases.
269 #[doc(hidden)]
270 type __SubclassingType: ?Sized;
271}
272
273/// Marks class types whose implementation is defined in Rust.
274///
275/// This is used in [`define_class!`], and allows access to the instance
276/// variables that a given type declares, see that macro for details.
277///
278/// [`define_class!`]: crate::define_class
279//
280// Note: We mark this trait as not `unsafe` for better documentation, since
281// implementing it inside `define_class!` is not `unsafe`.
282//
283// Safety is ensured by `__UNSAFE_OFFSETS_CORRECT`.
284pub trait DefinedClass: ClassType {
285 /// A type representing the instance variables that this class carries.
286 type Ivars: Sized;
287
288 // TODO: Add `ivars_ptr(this: NonNull<Self>) -> NonNull<Self::Ivars>`?
289
290 /// Get a reference to the instance variable data that this object
291 /// carries.
292 #[inline]
293 #[track_caller]
294 fn ivars(&self) -> &Self::Ivars
295 where
296 Self: Sized, // Required because of MSRV
297 {
298 let ptr: NonNull<Self> = NonNull::from(self);
299 // SAFETY: The pointer is valid and initialized.
300 let ivars = unsafe { get_initialized_ivar_ptr(ptr) };
301 // SAFETY: The lifetime of the instance variable is tied to the object.
302 unsafe { ivars.as_ref() }
303 }
304
305 #[doc(hidden)]
306 fn __ivars_offset() -> isize;
307
308 #[doc(hidden)]
309 fn __drop_flag_offset() -> isize;
310
311 /// # Safety
312 ///
313 /// The ivar offset and drop flag offsets must be implemented correctly.
314 #[doc(hidden)]
315 const __UNSAFE_OFFSETS_CORRECT: ();
316}
317
318/// Marks types that represent specific protocols.
319///
320/// This is the protocol equivalent of [`ClassType`].
321///
322/// This is implemented automatically by the [`extern_protocol!`] macro for
323/// `dyn T`, where `T` is the protocol.
324///
325/// [`ClassType`]: crate::ClassType
326/// [`extern_protocol!`]: crate::extern_protocol
327///
328///
329/// # Safety
330///
331/// This is meant to be a sealed trait, and should not be implemented outside
332/// of the [`extern_protocol!`] macro.
333///
334///
335/// # Examples
336///
337/// Use the trait to access the [`AnyProtocol`] of different objects.
338///
339/// ```
340/// use objc2::ProtocolType;
341/// use objc2::runtime::NSObjectProtocol;
342/// // Get a protocol object representing the `NSObject` protocol
343/// let protocol = <dyn NSObjectProtocol>::protocol().expect("NSObject to have a protocol");
344/// assert_eq!(<dyn NSObjectProtocol>::NAME, protocol.name().to_str().unwrap());
345/// # // Ensure Foundation links on GNUStep
346/// # let _cls = objc2::class!(NSObject);
347/// ```
348///
349/// Use the [`extern_protocol!`] macro to implement and use this trait.
350///
351/// ```no_run
352/// use objc2::{extern_protocol, ProtocolType};
353///
354/// extern_protocol!(
355/// unsafe trait MyProtocol {}
356/// );
357///
358/// let protocol = <dyn MyProtocol>::protocol();
359/// ```
360pub unsafe trait ProtocolType {
361 /// The name of the Objective-C protocol that this type represents.
362 ///
363 /// This must not contain any NUL bytes.
364 //
365 // TODO: Convert this to CStr next time we do big changes to ProtocolType.
366 const NAME: &'static str;
367
368 /// Get a reference to the Objective-C protocol object that this type
369 /// represents.
370 ///
371 /// May register the protocol with the runtime if it wasn't already.
372 ///
373 /// Note that some protocols [are not registered with the runtime][p-obj],
374 /// depending on various factors. In those cases, this function may return
375 /// `None`.
376 ///
377 /// [p-obj]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProtocols.html#//apple_ref/doc/uid/TP30001163-CH15-TPXREF149
378 ///
379 ///
380 /// # Panics
381 ///
382 /// This may panic if something went wrong with getting or creating the
383 /// protocol, e.g. if the program is not properly linked to the framework
384 /// that defines the protocol.
385 fn protocol() -> Option<&'static AnyProtocol> {
386 get_protocol(Self::NAME)
387 }
388
389 #[doc(hidden)]
390 const __INNER: ();
391}
392
393// Outlined to reduce code size
394fn get_protocol(name: &str) -> Option<&'static AnyProtocol> {
395 let name = CString::new(name).expect("protocol name must be UTF-8");
396 AnyProtocol::get(&name)
397}
398
399// Split into separate traits for better diagnostics
400mod private {
401 pub trait SealedAllocAnyThread {}
402 pub trait SealedMainThreadOnly {}
403 pub trait SealedThreadKind {}
404}
405
406/// Marker trait for classes (and protocols) that are usable from any thread,
407/// i.e. the opposite of [`MainThreadOnly`].
408///
409/// This is mostly an implementation detail to expose the [`alloc`] method
410/// with different signatures depending on whether a class is main thread only
411/// or not. You can safely assume that things are safe to use from any thread,
412/// _unless_ they implement [`MainThreadOnly`], not only if they implement
413/// this trait.
414///
415///
416/// # Safety
417///
418/// This is a sealed trait, and should not need to be implemented; it is
419/// implemented automatically when you implement [`ClassType`].
420//
421// NOTE: Ideally this would be an auto trait that had a negative impl for
422// `MainThreadOnly`, something like:
423//
424// pub unsafe auto trait AnyThread {}
425// pub unsafe trait MainThreadOnly {}
426// impl<T: ?Sized + MainThreadOnly> !AnyThread for T {}
427//
428// This isn't possible in current Rust though, so we'll have to hack it.
429pub unsafe trait AllocAnyThread: private::SealedAllocAnyThread {
430 /// Allocate a new instance of the class.
431 ///
432 /// The return value can be used directly inside [`msg_send!`] to
433 /// initialize the object.
434 ///
435 /// [`msg_send!`]: crate::msg_send
436 #[inline]
437 fn alloc() -> Allocated<Self>
438 where
439 Self: Sized + ClassType,
440 {
441 // SAFETY:
442 // - It is always safe to (attempt to) allocate an object.
443 // - The object is of the correct type, since we've used the class
444 // from `Self::class`.
445 // - The object is safe to `dealloc` on the current thread (due to the
446 // `AnyThread` bound which guarantees it is not `MainThreadOnly`).
447 //
448 // While Xcode's Main Thread Checker doesn't report `alloc` and
449 // `dealloc` as unsafe from other threads, things like `NSView` and
450 // `NSWindow` still do a non-trivial amount of stuff on `dealloc`,
451 // even if the object is freshly `alloc`'d - which is why we disallow
452 // this.
453 //
454 // This also has the nice property that `Allocated<T>` is guaranteed
455 // to be allowed to `init` on the current thread.
456 //
457 // See also `MainThreadMarker::alloc`.
458 unsafe { Allocated::alloc(Self::class()) }
459 }
460}
461
462// The impl here is a bit bad for diagnostics, but required to prevent users
463// implementing the trait themselves.
464impl<'a, T: ?Sized + ClassType<ThreadKind = dyn AllocAnyThread + 'a>> private::SealedAllocAnyThread
465 for T
466{
467}
468unsafe impl<'a, T: ?Sized + ClassType<ThreadKind = dyn AllocAnyThread + 'a>> AllocAnyThread for T {}
469
470impl<P: ?Sized> private::SealedAllocAnyThread for ProtocolObject<P> {}
471unsafe impl<P: ?Sized + AllocAnyThread> AllocAnyThread for ProtocolObject<P> {}
472
473/// Marker trait for classes and protocols that are only safe to use on the
474/// main thread.
475///
476/// This is commonly used in GUI code like `AppKit` and `UIKit`, e.g.
477/// `UIWindow` is only usable from the application's main thread because it
478/// accesses global statics like the `UIApplication`.
479///
480/// See [`MainThreadMarker`] for a few more details on this.
481///
482///
483/// # Safety
484///
485/// It is unsound to implement [`Send`] or [`Sync`] together with this.
486///
487/// This is a sealed trait, and should not need to be implemented; it is
488/// implemented automatically when you implement [`ClassType`].
489#[doc(alias = "@MainActor")]
490pub unsafe trait MainThreadOnly: private::SealedMainThreadOnly {
491 /// Get a [`MainThreadMarker`] from the main-thread-only object.
492 ///
493 /// This function exists purely in the type-system, and will succeed at
494 /// runtime (with a safety check when debug assertions are enabled).
495 #[inline]
496 #[cfg_attr(debug_assertions, track_caller)]
497 fn mtm(&self) -> MainThreadMarker {
498 #[cfg(debug_assertions)]
499 assert!(
500 MainThreadMarker::new().is_some(),
501 "the main-thread-only object that we tried to fetch a MainThreadMarker from was somehow not on the main thread",
502 );
503
504 // SAFETY: Objects which are `MainThreadOnly` are guaranteed
505 // `!Send + !Sync` and are only constructible on the main thread.
506 //
507 // Since we hold `&self`, i.e. a reference to such an object, and we
508 // know it cannot possibly be on another thread than the main, we know
509 // that the current thread is the main thread.
510 unsafe { MainThreadMarker::new_unchecked() }
511 }
512
513 /// Allocate a new instance of the class on the main thread.
514 ///
515 ///
516 /// # Example
517 ///
518 /// Create a view on the main thread.
519 ///
520 /// ```
521 /// use objc2::{MainThreadOnly, MainThreadMarker};
522 /// # #[cfg(available_in_app_kit)]
523 /// use objc2_app_kit::NSView;
524 /// use objc2_core_foundation::CGRect;
525 /// #
526 /// # use objc2::rc::{Allocated, Retained};
527 /// #
528 /// # objc2::extern_class!(
529 /// # #[unsafe(super(objc2::runtime::NSObject))]
530 /// # #[thread_kind = MainThreadOnly]
531 /// # #[name = "NSObject"] // For example
532 /// # struct NSView;
533 /// # );
534 /// #
535 /// # impl NSView {
536 /// # fn initWithFrame(this: Allocated<Self>, _frame: CGRect) -> Retained<Self> {
537 /// # // Don't use frame, this is NSObject
538 /// # unsafe { objc2::msg_send![this, init] }
539 /// # }
540 /// # }
541 ///
542 /// # #[cfg(doctests_not_always_run_on_main_thread)]
543 /// let mtm = MainThreadMarker::new().expect("must be on the main thread");
544 /// # let mtm = unsafe { MainThreadMarker::new_unchecked() };
545 ///
546 /// let frame = CGRect::default();
547 /// let view = NSView::initWithFrame(NSView::alloc(mtm), frame);
548 /// ```
549 #[inline]
550 fn alloc(mtm: MainThreadMarker) -> Allocated<Self>
551 where
552 Self: Sized + ClassType,
553 {
554 let _ = mtm;
555 // SAFETY: We hold `MainThreadMarker`, and the class is safe to
556 // allocate on the main thread.
557 unsafe { Allocated::alloc(Self::class()) }
558 }
559}
560
561impl<'a, T: ?Sized + ClassType<ThreadKind = dyn MainThreadOnly + 'a>> private::SealedMainThreadOnly
562 for T
563{
564}
565unsafe impl<'a, T: ?Sized + ClassType<ThreadKind = dyn MainThreadOnly + 'a>> MainThreadOnly for T {}
566
567impl<P: ?Sized> private::SealedMainThreadOnly for ProtocolObject<P> {}
568unsafe impl<P: ?Sized + MainThreadOnly> MainThreadOnly for ProtocolObject<P> {}
569
570/// The allowed values in [`ClassType::ThreadKind`].
571///
572/// One of [`dyn AllocAnyThread`] or [`dyn MainThreadOnly`].
573///
574/// [`dyn AllocAnyThread`]: AllocAnyThread
575/// [`dyn MainThreadOnly`]: MainThreadOnly
576pub trait ThreadKind: private::SealedThreadKind {
577 // To mark `ThreadKind` as dyn-incompatible for now.
578 #[doc(hidden)]
579 const __DYN_INCOMPATIBLE: ();
580}
581
582impl private::SealedThreadKind for dyn AllocAnyThread + '_ {}
583impl ThreadKind for dyn AllocAnyThread + '_ {
584 const __DYN_INCOMPATIBLE: () = ();
585}
586
587impl private::SealedThreadKind for dyn MainThreadOnly + '_ {}
588impl ThreadKind for dyn MainThreadOnly + '_ {
589 const __DYN_INCOMPATIBLE: () = ();
590}
591
592#[cfg(test)]
593mod tests {
594 use super::*;
595
596 #[allow(unused)]
597 fn dyn_compatible(_: &dyn AllocAnyThread, _: &dyn MainThreadOnly) {}
598}