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}