objc2/runtime/
mod.rs

1//! # Direct runtime bindings.
2//!
3//! This module contains safe(r) bindings to common parts of the Objective-C
4//! runtime. See the [`ffi`][crate::ffi] module for details on the raw
5//! bindings.
6//!
7//!
8//! # Example
9//!
10//! Using features of the runtime to query information about `NSObject`.
11//!
12//! ```
13#![doc = include_str!("../../examples/introspection.rs")]
14//! ```
15#![allow(clippy::missing_panics_doc)]
16
17use alloc::ffi::CString;
18use alloc::vec::Vec;
19use core::ffi::c_char;
20use core::ffi::c_uint;
21use core::ffi::{c_void, CStr};
22use core::fmt;
23use core::hash;
24use core::panic::{RefUnwindSafe, UnwindSafe};
25use core::ptr::{self, NonNull};
26
27// Note: While this is not public, it is still a breaking change to remove,
28// since `objc2-foundation` relies on it.
29#[doc(hidden)]
30pub mod __nsstring;
31mod bool;
32mod define;
33mod malloc;
34mod message_receiver;
35mod method_encoding_iter;
36mod method_implementation;
37mod nsobject;
38mod nsproxy;
39mod nszone;
40mod protocol_object;
41mod retain_release_fast;
42
43pub(crate) use self::method_encoding_iter::{EncodingParseError, MethodEncodingIter};
44pub(crate) use self::retain_release_fast::{objc_release_fast, objc_retain_fast};
45use crate::encode::{Encode, EncodeArguments, EncodeReturn, Encoding, OptionEncode, RefEncode};
46use crate::msg_send;
47use crate::verify::{verify_method_signature, Inner};
48use crate::{ffi, DowncastTarget, Message};
49
50// Note: While this is not public, it is still a breaking change to remove,
51// since `objc2-foundation` relies on it.
52#[doc(hidden)]
53pub use self::nsproxy::NSProxy as __NSProxy;
54
55pub use self::bool::Bool;
56pub use self::define::{ClassBuilder, ProtocolBuilder};
57pub use self::message_receiver::MessageReceiver;
58pub use self::method_implementation::MethodImplementation;
59pub use self::nsobject::{NSObject, NSObjectProtocol};
60pub use self::nszone::NSZone;
61pub use self::protocol_object::{ImplementedBy, ProtocolObject};
62pub use crate::verify::VerificationError;
63
64#[allow(deprecated)]
65pub use crate::ffi::{BOOL, NO, YES};
66
67use self::malloc::{MallocCStr, MallocSlice};
68
69/// We do not want to expose `MallocSlice` to end users, because in the
70/// future, we want to be able to change it to `Box<[T], MallocAllocator>`.
71///
72/// So instead we use an unnameable type.
73macro_rules! MallocSlice {
74    ($t:ty) => {
75        impl std::ops::Deref<Target = [$t]> + AsRef<[$t]> + std::fmt::Debug
76    };
77}
78
79/// Same as `MallocSlice!`.
80macro_rules! MallocCStr {
81    () => {
82        impl std::ops::Deref<Target = CStr> + AsRef<CStr> + std::fmt::Debug
83    };
84}
85
86/// Implement PartialEq, Eq and Hash using pointer semantics; there's not
87/// really a better way to do it for this type
88macro_rules! standard_pointer_impls {
89    ($name:ident) => {
90        impl PartialEq for $name {
91            #[inline]
92            fn eq(&self, other: &Self) -> bool {
93                ptr::eq(self, other)
94            }
95        }
96        impl Eq for $name {}
97        impl hash::Hash for $name {
98            #[inline]
99            fn hash<H: hash::Hasher>(&self, state: &mut H) {
100                let ptr: *const Self = self;
101                ptr.hash(state)
102            }
103        }
104    };
105}
106
107/// A pointer to the start of a method implementation.
108///
109/// The first argument is a pointer to the receiver, the second argument is
110/// the selector, and the rest of the arguments follow.
111///
112///
113/// # Safety
114///
115/// This is a "catch all" type; it must be transmuted to the correct type
116/// before being called!
117///
118/// Also note that this is non-null! If you require an Imp that can be null,
119/// use `Option<Imp>`.
120#[doc(alias = "IMP")]
121pub type Imp = unsafe extern "C-unwind" fn();
122
123/// A method selector.
124///
125/// The Rust equivalent of Objective-C's `SEL _Nonnull` type. You can create
126/// this statically using the [`sel!`] macro.
127///
128/// The main reason the Objective-C runtime uses a custom type for selectors,
129/// as opposed to a plain c-string, is to support efficient comparison - a
130/// a selector is effectively an [interned string], so this makes equiality
131/// comparisons very cheap.
132///
133/// This struct guarantees the null-pointer optimization, namely that
134/// `Option<Sel>` is the same size as `Sel`.
135///
136/// Selectors are immutable.
137///
138/// [`sel!`]: crate::sel
139/// [interned string]: https://en.wikipedia.org/wiki/String_interning
140#[repr(transparent)]
141#[derive(Copy, Clone)]
142#[doc(alias = "SEL")]
143#[doc(alias = "objc_selector")]
144pub struct Sel {
145    ptr: NonNull<c_void>,
146}
147
148// SAFETY: Sel is immutable (and can be retrieved from any thread using the
149// `sel!` macro).
150unsafe impl Sync for Sel {}
151unsafe impl Send for Sel {}
152impl UnwindSafe for Sel {}
153impl RefUnwindSafe for Sel {}
154
155impl Sel {
156    #[inline]
157    #[doc(hidden)]
158    pub const unsafe fn __internal_from_ptr(ptr: *const u8) -> Self {
159        // Used in static selectors.
160        // SAFETY: Upheld by caller.
161        let ptr = unsafe { NonNull::new_unchecked(ptr as *mut c_void) };
162        Self { ptr }
163    }
164
165    #[inline]
166    pub(crate) unsafe fn from_ptr(ptr: *const c_void) -> Option<Self> {
167        // SAFETY: Caller verifies that the pointer is valid.
168        NonNull::new(ptr as *mut c_void).map(|ptr| Self { ptr })
169    }
170
171    #[inline]
172    pub(crate) const fn as_ptr(&self) -> *const c_void {
173        self.ptr.as_ptr()
174    }
175
176    // We explicitly don't do #[track_caller] here, since we expect the error
177    // to never actually happen.
178    pub(crate) unsafe fn register_unchecked(name: *const c_char) -> Self {
179        let ptr = unsafe { ffi::sel_registerName(name) };
180        // SAFETY: `sel_registerName` declares return type as `SEL _Nonnull`,
181        // at least when input is also `_Nonnull` (which it is in our case).
182        //
183        // Looking at the source code, it can fail and will return NULL if
184        // allocating space for the selector failed (which then subsequently
185        // invokes UB by calling `memcpy` with a NULL argument):
186        // <https://github.com/apple-oss-distributions/objc4/blob/objc4-841.13/runtime/objc-os.h#L1002-L1004>
187        //
188        // I suspect this will be really uncommon in practice, since the
189        // called selector is almost always going to be present in the binary
190        // already; but alas, we'll handle it!
191        ptr.expect("failed allocating selector")
192    }
193
194    /// Registers a selector with the Objective-C runtime.
195    ///
196    /// This is the dynamic version of the [`sel!`] macro, prefer to use that
197    /// when your selector is static.
198    ///
199    /// [`sel!`]: crate::sel
200    ///
201    ///
202    /// # Panics
203    ///
204    /// Panics if the runtime failed allocating space for the selector.
205    #[inline]
206    #[doc(alias = "sel_registerName")]
207    pub fn register(name: &CStr) -> Self {
208        // SAFETY: Input is a non-null, NUL-terminated C-string pointer.
209        unsafe { Self::register_unchecked(name.as_ptr()) }
210    }
211
212    /// Returns the string representation of the selector.
213    #[inline]
214    #[doc(alias = "sel_getName")]
215    pub fn name(self) -> &'static CStr {
216        // SAFETY: Input is non-null selector. Declares return type as
217        // `const char * _Nonnull`, source code agrees.
218        let ptr = unsafe { ffi::sel_getName(self) };
219        // SAFETY: The string is a valid C-style NUL-terminated string, and
220        // has static lifetime since the selector has static lifetime.
221        unsafe { CStr::from_ptr(ptr) }
222    }
223
224    pub(crate) fn number_of_arguments(self) -> usize {
225        self.name()
226            .to_bytes()
227            .iter()
228            .filter(|&&b| b == b':')
229            .count()
230    }
231}
232
233impl PartialEq for Sel {
234    #[inline]
235    fn eq(&self, other: &Self) -> bool {
236        if cfg!(feature = "gnustep-1-7") {
237            // GNUStep implements "typed" selectors, which means their pointer
238            // values sometimes differ; so let's use the runtime-provided
239            // `sel_isEqual`.
240            unsafe { ffi::sel_isEqual(*self, *other).as_bool() }
241        } else {
242            // `ffi::sel_isEqual` uses pointer comparison on Apple (the
243            // documentation explicitly notes this); so as an optimization,
244            // let's do that as well!
245            self.as_ptr() == other.as_ptr()
246        }
247    }
248}
249
250impl Eq for Sel {}
251
252impl hash::Hash for Sel {
253    #[inline]
254    fn hash<H: hash::Hasher>(&self, state: &mut H) {
255        if cfg!(feature = "gnustep-1-7") {
256            // Note: We hash the name instead of the pointer on GNUStep, since
257            // they're typed.
258            self.name().hash(state);
259        } else {
260            self.as_ptr().hash(state);
261        }
262    }
263}
264
265// SAFETY: `Sel` is FFI compatible, and the encoding is `Sel`.
266unsafe impl Encode for Sel {
267    const ENCODING: Encoding = Encoding::Sel;
268}
269
270unsafe impl OptionEncode for Sel {}
271
272// RefEncode is not implemented for Sel, because there is literally no API
273// that takes &Sel, while the user could get confused and accidentally attempt
274// that.
275
276impl fmt::Display for Sel {
277    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278        // Selectors are basically always UTF-8, so it's _fine_ to do a lossy
279        // conversion here.
280        fmt::Display::fmt(&self.name().to_string_lossy(), f)
281    }
282}
283
284impl fmt::Debug for Sel {
285    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286        f.debug_tuple("Sel").field(&self.name()).finish()
287    }
288}
289
290impl fmt::Pointer for Sel {
291    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
292        fmt::Pointer::fmt(&self.ptr, f)
293    }
294}
295
296/// An opaque type that represents an instance variable.
297///
298/// See [Apple's documentation](https://developer.apple.com/documentation/objectivec/ivar?language=objc).
299#[repr(C)]
300#[doc(alias = "objc_ivar")]
301pub struct Ivar {
302    _priv: [u8; 0],
303    _p: ffi::OpaqueData,
304}
305
306// SAFETY: Ivar is immutable (and can be retrieved from AnyClass anyhow).
307unsafe impl Sync for Ivar {}
308unsafe impl Send for Ivar {}
309impl UnwindSafe for Ivar {}
310impl RefUnwindSafe for Ivar {}
311
312impl Ivar {
313    /// Returns the instance variable's name.
314    ///
315    /// See [Apple's documentation](https://developer.apple.com/documentation/objectivec/1418922-ivar_getname?language=objc).
316    #[inline]
317    #[doc(alias = "ivar_getName")]
318    pub fn name(&self) -> &CStr {
319        unsafe { CStr::from_ptr(ffi::ivar_getName(self)) }
320    }
321
322    /// Returns the instance variable's offset from the object base.
323    ///
324    /// See [Apple's documentation](https://developer.apple.com/documentation/objectivec/1418976-ivar_getoffset?language=objc).
325    #[inline]
326    #[doc(alias = "ivar_getOffset")]
327    pub fn offset(&self) -> isize {
328        unsafe { ffi::ivar_getOffset(self) }
329    }
330
331    /// Returns the instance variable's `@encode(type)` string.
332    ///
333    /// See [Apple's documentation](https://developer.apple.com/documentation/objectivec/1418569-ivar_gettypeencoding?language=objc).
334    #[inline]
335    #[doc(alias = "ivar_getTypeEncoding")]
336    pub fn type_encoding(&self) -> &CStr {
337        unsafe { CStr::from_ptr(ffi::ivar_getTypeEncoding(self)) }
338    }
339
340    #[inline]
341    pub(crate) fn debug_assert_encoding(&self, _expected: &Encoding) {
342        #[cfg(all(debug_assertions, not(feature = "disable-encoding-assertions")))]
343        {
344            let encoding = self.type_encoding();
345            let encoding = encoding.to_str().expect("encoding must be UTF-8");
346            assert!(
347                _expected.equivalent_to_str(encoding),
348                "wrong encoding. Tried to retrieve ivar with encoding {encoding}, but the encoding of the given type was {_expected}",
349            );
350        }
351    }
352
353    /// Returns a pointer to the instance variable / ivar on the given object.
354    ///
355    /// This is similar to [`UnsafeCell::get`], see that for more information
356    /// on what is and isn't safe to do.
357    ///
358    /// Usually you will have defined the instance variable yourself with
359    /// [`ClassBuilder::add_ivar`], the type of the ivar `T` must match the
360    /// type used in that.
361    ///
362    /// Library implementors are strongly encouraged to expose a safe
363    /// interface to the ivar.
364    ///
365    /// [`UnsafeCell::get`]: core::cell::UnsafeCell::get
366    /// [`ClassBuilder::add_ivar`]: crate::runtime::ClassBuilder::add_ivar
367    ///
368    ///
369    /// # Panics
370    ///
371    /// Panics when `debug_assertions` are enabled if the type encoding of the
372    /// ivar differs from the type encoding of `T`. This can be disabled with
373    /// the `"disable-encoding-assertions"` Cargo feature flag.
374    ///
375    ///
376    /// # Safety
377    ///
378    /// The object must have the given instance variable on it, and it must be
379    /// of type `T`. Any invariants that the object have assumed about the
380    /// value of the instance variable must not be violated.
381    ///
382    /// Note that an object can have multiple instance variables with the same
383    /// name; you must ensure that when the instance variable was retrieved,
384    /// was retrieved from the class that it was defined on. In particular,
385    /// getting a class dynamically using e.g. [`AnyObject::class`], and using
386    /// an instance variable from that here is _not_ sound in general.
387    ///
388    /// No thread synchronization is done on accesses to the variable, so you
389    /// must ensure that any access to the returned pointer do not cause data
390    /// races, and that Rust's mutability rules are not otherwise violated.
391    #[inline]
392    pub unsafe fn load_ptr<T: Encode>(&self, obj: &AnyObject) -> *mut T {
393        self.debug_assert_encoding(&T::ENCODING);
394
395        let ptr = NonNull::from(obj);
396        // SAFETY: That the ivar is valid is ensured by the caller
397        let ptr = unsafe { AnyObject::ivar_at_offset::<T>(ptr, self.offset()) };
398
399        // Safe as *mut T because `self` is `UnsafeCell`
400        ptr.as_ptr()
401    }
402
403    /// Returns a reference to the instance variable with the given name.
404    ///
405    /// See [`Ivar::load_ptr`] for more information.
406    ///
407    ///
408    /// # Panics
409    ///
410    /// Panics when `debug_assertions` are enabled if the type encoding of the
411    /// ivar differs from the type encoding of `T`. This can be disabled with
412    /// the `"disable-encoding-assertions"` Cargo feature flag.
413    ///
414    ///
415    /// # Safety
416    ///
417    /// The object must have the given instance variable on it, and it must be
418    /// of type `T`.
419    ///
420    /// No thread synchronization is done, so you must ensure that no other
421    /// thread is concurrently mutating the variable. This requirement can be
422    /// considered upheld if all mutation happens through [`Ivar::load_mut`]
423    /// (since that takes the object mutably).
424    #[inline]
425    pub unsafe fn load<'obj, T: Encode>(&self, obj: &'obj AnyObject) -> &'obj T {
426        // SAFETY: That the ivar is valid as `&T` is ensured by the caller,
427        // and the reference is properly bound to the object.
428        unsafe { self.load_ptr::<T>(obj).as_ref().unwrap_unchecked() }
429    }
430
431    /// Returns a mutable reference to the ivar with the given name.
432    ///
433    /// See [`Ivar::load_ptr`] for more information.
434    ///
435    ///
436    /// # Panics
437    ///
438    /// Panics when `debug_assertions` are enabled if the type encoding of the
439    /// ivar differs from the type encoding of `T`. This can be disabled with
440    /// the `"disable-encoding-assertions"` Cargo feature flag.
441    ///
442    ///
443    /// # Safety
444    ///
445    /// The object must have an instance variable with the given name, and it
446    /// must be of type `T`.
447    ///
448    /// This access happens through `&mut`, which means we know it to be the
449    /// only reference, hence you do not need to do any work to ensure that
450    /// data races do not happen.
451    #[inline]
452    pub unsafe fn load_mut<'obj, T: Encode>(&self, obj: &'obj mut AnyObject) -> &'obj mut T {
453        self.debug_assert_encoding(&T::ENCODING);
454
455        let ptr = NonNull::from(obj);
456        // SAFETY: That the ivar is valid is ensured by the caller
457        let mut ptr = unsafe { AnyObject::ivar_at_offset::<T>(ptr, self.offset()) };
458
459        // SAFETY: That the ivar is valid as `&mut T` is ensured by taking an
460        // `&mut` object
461        unsafe { ptr.as_mut() }
462    }
463}
464
465standard_pointer_impls!(Ivar);
466
467impl fmt::Debug for Ivar {
468    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469        f.debug_struct("Ivar")
470            .field("name", &self.name())
471            .field("offset", &self.offset())
472            .field("type_encoding", &self.type_encoding())
473            .finish_non_exhaustive()
474    }
475}
476
477#[derive(Debug, PartialEq, Eq, Hash)]
478pub(crate) struct MethodDescription {
479    pub(crate) sel: Sel,
480    pub(crate) types: &'static CStr,
481}
482
483impl MethodDescription {
484    pub(crate) unsafe fn from_raw(raw: ffi::objc_method_description) -> Option<Self> {
485        let sel = raw.name?;
486        if raw.types.is_null() {
487            return None;
488        }
489        // SAFETY: We've checked that the pointer is not NULL, rest is checked
490        // by caller.
491        let types = unsafe { CStr::from_ptr(raw.types) };
492        Some(Self { sel, types })
493    }
494}
495
496/// A type that represents a method in a class definition.
497///
498/// See [Apple's documentation](https://developer.apple.com/documentation/objectivec/method?language=objc).
499#[repr(C)]
500#[doc(alias = "objc_method")]
501pub struct Method {
502    _priv: [u8; 0],
503    _p: ffi::OpaqueData,
504}
505
506// SAFETY: Method is immutable (and can be retrieved from AnyClass anyhow).
507unsafe impl Sync for Method {}
508unsafe impl Send for Method {}
509impl UnwindSafe for Method {}
510impl RefUnwindSafe for Method {}
511
512impl Method {
513    // Note: We don't take `&mut` here, since the operations on methods work
514    // atomically.
515    #[inline]
516    fn as_mut_ptr(&self) -> *mut Self {
517        let ptr: *const Self = self;
518        ptr as _
519    }
520
521    /// Returns the name of self.
522    #[inline]
523    #[doc(alias = "method_getName")]
524    pub fn name(&self) -> Sel {
525        unsafe { ffi::method_getName(self).unwrap() }
526    }
527
528    /// Returns the `Encoding` of self's return type.
529    #[doc(alias = "method_copyReturnType")]
530    pub fn return_type(&self) -> MallocCStr!() {
531        unsafe {
532            let encoding = ffi::method_copyReturnType(self);
533            MallocCStr::from_c_str(encoding)
534        }
535    }
536
537    /// Returns the `Encoding` of a single parameter type of self, or
538    /// [`None`] if self has no parameter at the given index.
539    #[doc(alias = "method_copyArgumentType")]
540    pub fn argument_type(&self, index: usize) -> Option<MallocCStr!()> {
541        unsafe {
542            let encoding = ffi::method_copyArgumentType(self, index as c_uint);
543            NonNull::new(encoding).map(|encoding| MallocCStr::from_c_str(encoding.as_ptr()))
544        }
545    }
546
547    /// An iterator over the method's types.
548    ///
549    /// It is approximately equivalent to:
550    ///
551    /// ```ignore
552    /// let types = method.types();
553    /// assert_eq!(types.next()?, method.return_type());
554    /// for i in 0..method.arguments_count() {
555    ///    assert_eq!(types.next()?, method.argument_type(i)?);
556    /// }
557    /// assert!(types.next().is_none());
558    /// ```
559    #[doc(alias = "method_getTypeEncoding")]
560    pub(crate) fn types(&self) -> MethodEncodingIter<'_> {
561        // SAFETY: The method pointer is valid and non-null
562        let cstr = unsafe { ffi::method_getTypeEncoding(self) };
563        if cstr.is_null() {
564            panic!("method type encoding was NULL");
565        }
566        // SAFETY: `method_getTypeEncoding` returns a C-string, and we just
567        // checked that it is non-null.
568        let encoding = unsafe { CStr::from_ptr(cstr) };
569        let s = encoding
570            .to_str()
571            .expect("method type encoding must be UTF-8");
572        MethodEncodingIter::new(s)
573    }
574
575    /// Returns the number of arguments accepted by self.
576    #[inline]
577    #[doc(alias = "method_getNumberOfArguments")]
578    pub fn arguments_count(&self) -> usize {
579        unsafe { ffi::method_getNumberOfArguments(self) as usize }
580    }
581
582    /// Returns the implementation of this method.
583    #[doc(alias = "method_getImplementation")]
584    pub fn implementation(&self) -> Imp {
585        unsafe { ffi::method_getImplementation(self).expect("null IMP") }
586    }
587
588    /// Set the implementation of this method.
589    ///
590    /// Note that any thread may at any point be changing method
591    /// implementations, so if you intend to call the previous method as
592    /// returned by e.g. [`Self::implementation`], beware that that may now be
593    /// stale.
594    ///
595    /// The previous implementation is returned from this function though, so
596    /// you can call that instead.
597    ///
598    /// See [Apple's documentation](https://developer.apple.com/documentation/objectivec/1418707-method_setimplementation?language=objc).
599    ///
600    ///
601    /// # Safety
602    ///
603    /// The given implementation function pointer must:
604    ///
605    /// 1. Have the signature expected by the Objective-C runtime and callers
606    ///    of this method.
607    ///
608    /// 2. Be at least as safe as the existing method, i.e. by overriding the
609    ///    previous method, it should not be possible for the program to cause
610    ///    UB.
611    ///
612    ///    A common mistake would be expecting e.g. a pointer to not be null,
613    ///    where the null case was handled before.
614    #[doc(alias = "method_setImplementation")]
615    pub unsafe fn set_implementation(&self, imp: Imp) -> Imp {
616        // SAFETY: The new impl is not NULL, and the rest is upheld by the
617        // caller.
618        unsafe { ffi::method_setImplementation(self.as_mut_ptr(), imp).expect("null IMP") }
619    }
620
621    /// Exchange the implementation of two methods.
622    ///
623    /// See [Apple's documentation](https://developer.apple.com/documentation/objectivec/1418769-method_exchangeimplementations?language=objc).
624    ///
625    ///
626    /// # Safety
627    ///
628    /// The two methods must be perfectly compatible, both in signature, and
629    /// in expected (in terms of safety, not necessarily behaviour) input and
630    /// output.
631    ///
632    ///
633    /// # Example
634    ///
635    /// This is an atomic version of the following:
636    ///
637    /// ```
638    /// use objc2::runtime::Method;
639    /// # use objc2::runtime::NSObject;
640    /// # use objc2::sel;
641    /// # use crate::objc2::ClassType;
642    ///
643    /// let m1: &Method;
644    /// let m2: &Method;
645    /// #
646    /// # // Use the same method twice, to avoid actually changing anything
647    /// # m1 = NSObject::class().instance_method(sel!(hash)).unwrap();
648    /// # m2 = NSObject::class().instance_method(sel!(hash)).unwrap();
649    ///
650    /// unsafe {
651    ///     let imp = m2.set_implementation(m1.implementation());
652    ///     m1.set_implementation(imp);
653    /// }
654    /// ```
655    #[inline]
656    #[doc(alias = "method_exchangeImplementations")]
657    pub unsafe fn exchange_implementation(&self, other: &Self) {
658        // TODO: Consider checking that `self.types()` and `other.types()`
659        // match when debug assertions are enabled?
660
661        // SAFETY: Verified by caller
662        unsafe { ffi::method_exchangeImplementations(self.as_mut_ptr(), other.as_mut_ptr()) }
663    }
664}
665
666standard_pointer_impls!(Method);
667
668impl fmt::Debug for Method {
669    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
670        f.debug_struct("Method")
671            .field("name", &self.name())
672            .field("types", &self.types())
673            .field("implementation", &self.implementation())
674            .finish_non_exhaustive()
675    }
676}
677
678/// An opaque type that represents an Objective-C class.
679///
680/// This is an opaque type meant to be used behind a shared reference
681/// `&AnyClass`, which is semantically equivalent to `Class _Nonnull`.
682///
683/// A nullable class can be used as `Option<&AnyClass>`.
684///
685/// See [Apple's documentation](https://developer.apple.com/documentation/objectivec/class?language=objc).
686#[repr(C)]
687#[doc(alias = "Class")]
688#[doc(alias = "objc_class")]
689pub struct AnyClass {
690    // `isa` field is deprecated and not available on GNUStep, so we don't
691    // expose it here. Use `class_getSuperclass` instead.
692    inner: AnyObject,
693}
694
695/// Use [`AnyClass`] instead.
696#[deprecated = "renamed to `runtime::AnyClass`"]
697pub type Class = AnyClass;
698
699// SAFETY: AnyClass is immutable (and can be retrieved from any thread using
700// the `class!` macro).
701unsafe impl Sync for AnyClass {}
702unsafe impl Send for AnyClass {}
703impl UnwindSafe for AnyClass {}
704impl RefUnwindSafe for AnyClass {}
705// Note that Unpin is not applicable.
706
707impl AnyClass {
708    /// Returns the class definition of a specified class, or [`None`] if the
709    /// class is not registered with the Objective-C runtime.
710    #[inline]
711    #[doc(alias = "objc_getClass")]
712    pub fn get(name: &CStr) -> Option<&'static Self> {
713        let cls = unsafe { ffi::objc_getClass(name.as_ptr()) };
714        unsafe { cls.as_ref() }
715    }
716
717    // Same as `get`, but ...
718    // fn lookup(name: &CStr) -> Option<&'static Self>;
719
720    /// Obtains the list of registered class definitions.
721    #[doc(alias = "objc_copyClassList")]
722    pub fn classes() -> MallocSlice!(&'static Self) {
723        unsafe {
724            let mut count: c_uint = 0;
725            let classes: *mut &Self = ffi::objc_copyClassList(&mut count).cast();
726            MallocSlice::from_array(classes, count as usize)
727        }
728    }
729
730    /// Returns the total number of registered classes.
731    #[inline]
732    #[doc(alias = "objc_getClassList")]
733    pub fn classes_count() -> usize {
734        unsafe { ffi::objc_getClassList(ptr::null_mut(), 0) as usize }
735    }
736
737    /// # Safety
738    ///
739    /// 1. The class pointer must be valid.
740    /// 2. The string is unbounded, so the caller must bound it.
741    pub(crate) unsafe fn name_raw<'a>(ptr: *const Self) -> &'a CStr {
742        // SAFETY: Caller ensures that the pointer is valid
743        let name = unsafe { ffi::class_getName(ptr) };
744        if name.is_null() {
745            panic!("class name was NULL");
746        }
747        // SAFETY: We've checked that the pointer is not NULL, and
748        // `class_getName` is guaranteed to return a valid C-string.
749        //
750        // That the result is properly bounded is checked by the caller.
751        unsafe { CStr::from_ptr(name) }
752    }
753
754    /// Returns the name of the class.
755    #[inline]
756    #[doc(alias = "class_getName")]
757    pub fn name(&self) -> &CStr {
758        // SAFETY: The pointer is valid, and the return is properly bounded
759        unsafe { Self::name_raw(self) }
760    }
761
762    /// # Safety
763    ///
764    /// 1. The class pointer must be valid.
765    /// 2. The caller must bound the lifetime of the returned class.
766    #[inline]
767    pub(crate) unsafe fn superclass_raw<'a>(ptr: *const Self) -> Option<&'a AnyClass> {
768        // SAFETY: Caller ensures that the pointer is valid
769        let superclass = unsafe { ffi::class_getSuperclass(ptr) };
770        // SAFETY: The result is properly bounded by the caller.
771        unsafe { superclass.as_ref() }
772    }
773
774    /// Returns the superclass of self, or [`None`] if self is a root class.
775    #[inline]
776    #[doc(alias = "class_getSuperclass")]
777    pub fn superclass(&self) -> Option<&AnyClass> {
778        // SAFETY: The pointer is valid, and the return is properly bounded
779        unsafe { Self::superclass_raw(self) }
780    }
781
782    /// Returns the metaclass of self.
783    ///
784    ///
785    /// # Example
786    ///
787    /// Get the metaclass of an object.
788    ///
789    /// ```
790    /// use objc2::runtime::NSObject;
791    /// use objc2::ClassType;
792    ///
793    /// let cls = NSObject::class();
794    /// let metacls = cls.metaclass();
795    ///
796    /// assert_eq!(metacls.name(), c"NSObject");
797    /// ```
798    #[inline]
799    #[doc(alias = "object_getClass")]
800    #[doc(alias = "objc_getMetaClass")] // Same as `AnyClass::get(name).metaclass()`
801    pub fn metaclass(&self) -> &Self {
802        let ptr: *const Self = self;
803        let ptr = unsafe { ffi::object_getClass(ptr.cast()) };
804        unsafe { ptr.as_ref().unwrap_unchecked() }
805    }
806
807    /// Whether the class is a metaclass.
808    ///
809    ///
810    /// # Example
811    ///
812    /// ```
813    /// use objc2::runtime::NSObject;
814    /// use objc2::ClassType;
815    ///
816    /// let cls = NSObject::class();
817    /// let metacls = cls.metaclass();
818    ///
819    /// assert!(!cls.is_metaclass());
820    /// assert!(metacls.is_metaclass());
821    /// ```
822    #[inline]
823    #[doc(alias = "class_isMetaClass")]
824    pub fn is_metaclass(&self) -> bool {
825        unsafe { ffi::class_isMetaClass(self).as_bool() }
826    }
827
828    /// Returns the size of instances of self.
829    #[inline]
830    #[doc(alias = "class_getInstanceSize")]
831    pub fn instance_size(&self) -> usize {
832        unsafe { ffi::class_getInstanceSize(self) }
833    }
834
835    /// Returns a specified instance method for self, or [`None`] if self and
836    /// its superclasses do not contain an instance method with the specified
837    /// selector.
838    #[inline]
839    #[doc(alias = "class_getInstanceMethod")]
840    pub fn instance_method(&self, sel: Sel) -> Option<&Method> {
841        unsafe {
842            let method = ffi::class_getInstanceMethod(self, sel);
843            method.as_ref()
844        }
845    }
846
847    /// Returns a specified class method for self, or [`None`] if self and
848    /// its superclasses do not contain a class method with the specified
849    /// selector.
850    ///
851    /// Same as `cls.metaclass().class_method()`.
852    #[inline]
853    #[doc(alias = "class_getClassMethod")]
854    pub fn class_method(&self, sel: Sel) -> Option<&Method> {
855        unsafe {
856            let method = ffi::class_getClassMethod(self, sel);
857            method.as_ref()
858        }
859    }
860
861    /// Returns the ivar for a specified instance variable of self, or
862    /// [`None`] if self has no ivar with the given name.
863    ///
864    /// If the instance variable was not found on the specified class, the
865    /// superclasses are searched.
866    ///
867    /// Attempting to access or modify instance variables of a class that you
868    /// do no control may invoke undefined behaviour.
869    #[inline]
870    #[doc(alias = "class_getInstanceVariable")]
871    pub fn instance_variable(&self, name: &CStr) -> Option<&Ivar> {
872        unsafe {
873            let ivar = ffi::class_getInstanceVariable(self, name.as_ptr());
874            ivar.as_ref()
875        }
876    }
877
878    #[allow(unused)]
879    #[inline]
880    #[doc(alias = "class_getClassVariable")]
881    fn class_variable(&self, name: &CStr) -> Option<&Ivar> {
882        let ivar = unsafe { ffi::class_getClassVariable(self, name.as_ptr()) };
883        // SAFETY: TODO
884        unsafe { ivar.as_ref() }
885    }
886
887    /// Describes the instance methods implemented by self.
888    #[doc(alias = "class_copyMethodList")]
889    pub fn instance_methods(&self) -> MallocSlice!(&Method) {
890        unsafe {
891            let mut count: c_uint = 0;
892            let methods: *mut &Method = ffi::class_copyMethodList(self, &mut count).cast();
893            MallocSlice::from_array(methods, count as usize)
894        }
895    }
896
897    /// Checks whether this class conforms to the specified protocol.
898    #[inline]
899    #[doc(alias = "class_conformsToProtocol")]
900    pub fn conforms_to(&self, proto: &AnyProtocol) -> bool {
901        unsafe { ffi::class_conformsToProtocol(self, proto).as_bool() }
902    }
903
904    /// Get a list of the protocols to which this class conforms.
905    #[doc(alias = "class_copyProtocolList")]
906    pub fn adopted_protocols(&self) -> MallocSlice!(&AnyProtocol) {
907        unsafe {
908            let mut count: c_uint = 0;
909            let protos: *mut &AnyProtocol = ffi::class_copyProtocolList(self, &mut count).cast();
910            MallocSlice::from_array(protos, count as usize)
911        }
912    }
913
914    /// Get a list of instance variables on the class.
915    #[doc(alias = "class_copyIvarList")]
916    pub fn instance_variables(&self) -> MallocSlice!(&Ivar) {
917        unsafe {
918            let mut count: c_uint = 0;
919            let ivars: *mut &Ivar = ffi::class_copyIvarList(self, &mut count).cast();
920            MallocSlice::from_array(ivars, count as usize)
921        }
922    }
923
924    /// Check whether instances of this class respond to the given selector.
925    ///
926    /// This doesn't call `respondsToSelector:`, but works entirely within the
927    /// runtime, which means it'll always be safe to call, but may not return
928    /// exactly what you'd expect if `respondsToSelector:` has been
929    /// overwritten.
930    ///
931    /// That said, it will always return `true` if an instance of the class
932    /// responds to the selector, but may return `false` if they don't
933    /// directly (e.g. does so by using forwarding instead).
934    #[inline]
935    #[doc(alias = "class_respondsToSelector")]
936    pub fn responds_to(&self, sel: Sel) -> bool {
937        // This may call `resolveInstanceMethod:` and `resolveClassMethod:`
938        // SAFETY: The selector is guaranteed non-null.
939        unsafe { ffi::class_respondsToSelector(self, sel).as_bool() }
940    }
941
942    // <https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html>
943    // fn property(&self, name: &CStr) -> Option<&Property>;
944    // fn properties(&self) -> MallocSlice!(&Property);
945    // unsafe fn replace_method(&self, name: Sel, imp: Imp, types: &CStr) -> Imp;
946    // unsafe fn replace_property(&self, name: &CStr, attributes: &[ffi::objc_property_attribute_t]);
947    // fn method_imp(&self, name: Sel) -> Imp; // + _stret
948
949    // fn get_version(&self) -> u32;
950    // unsafe fn set_version(&mut self, version: u32);
951
952    /// Verify argument and return types for a given selector.
953    ///
954    /// This will look up the encoding of the method for the given selector
955    /// and return a [`VerificationError`] if any encodings differ for the
956    /// arguments `A` and return type `R`.
957    ///
958    ///
959    /// # Example
960    ///
961    /// ```
962    /// use objc2::{class, sel};
963    /// use objc2::runtime::{AnyClass, Bool};
964    /// let cls = class!(NSObject);
965    /// let sel = sel!(isKindOfClass:);
966    /// // Verify that `isKindOfClass:`:
967    /// // - Exists on the class
968    /// // - Takes a class as a parameter
969    /// // - Returns a BOOL
970    /// let result = cls.verify_sel::<(&AnyClass,), Bool>(sel);
971    /// assert!(result.is_ok());
972    /// ```
973    #[allow(clippy::missing_errors_doc)] // Written differently in the docs
974    pub fn verify_sel<A, R>(&self, sel: Sel) -> Result<(), VerificationError>
975    where
976        A: EncodeArguments,
977        R: EncodeReturn,
978    {
979        let method = self.instance_method(sel).ok_or(Inner::MethodNotFound)?;
980        verify_method_signature(method, A::ENCODINGS, &R::ENCODING_RETURN)
981    }
982}
983
984standard_pointer_impls!(AnyClass);
985
986unsafe impl RefEncode for AnyClass {
987    const ENCODING_REF: Encoding = Encoding::Class;
988}
989
990// SAFETY: Classes act as objects, and can be sent messages.
991unsafe impl Message for AnyClass {}
992
993impl fmt::Debug for AnyClass {
994    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
995        f.debug_struct("AnyClass")
996            .field("name", &self.name())
997            .finish_non_exhaustive()
998    }
999}
1000
1001impl fmt::Display for AnyClass {
1002    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1003        // Classes are usually UTF-8, so it's probably fine to do a lossy
1004        // conversion here.
1005        fmt::Display::fmt(&self.name().to_string_lossy(), f)
1006    }
1007}
1008
1009impl AsRef<Self> for AnyClass {
1010    fn as_ref(&self) -> &Self {
1011        self
1012    }
1013}
1014
1015// This is the same as what Swift allows (`AnyClass` coerces to `AnyObject`).
1016impl AsRef<AnyObject> for AnyClass {
1017    fn as_ref(&self) -> &AnyObject {
1018        &self.inner
1019    }
1020}
1021
1022/// An opaque type that represents a protocol in the Objective-C runtime.
1023///
1024/// See [`ProtocolObject`] for objects that implement a specific protocol.
1025//
1026// The naming of this follows GNUStep; this struct does not exist in Apple's
1027// runtime, there `Protocol` is a type alias of `objc_object`.
1028#[repr(C)]
1029#[doc(alias = "objc_protocol")]
1030pub struct AnyProtocol {
1031    inner: AnyObject,
1032}
1033
1034/// Use [`AnyProtocol`] instead.
1035#[deprecated = "renamed to `runtime::AnyProtocol`"]
1036pub type Protocol = AnyProtocol;
1037
1038// SAFETY: AnyProtocol is immutable (and can be retrieved from AnyClass anyhow).
1039unsafe impl Sync for AnyProtocol {}
1040unsafe impl Send for AnyProtocol {}
1041impl UnwindSafe for AnyProtocol {}
1042impl RefUnwindSafe for AnyProtocol {}
1043// Note that Unpin is not applicable.
1044
1045impl AnyProtocol {
1046    /// Returns the protocol definition of a specified protocol, or [`None`]
1047    /// if the protocol is not registered with the Objective-C runtime.
1048    #[inline]
1049    #[doc(alias = "objc_getProtocol")]
1050    pub fn get(name: &CStr) -> Option<&'static Self> {
1051        unsafe {
1052            let proto = ffi::objc_getProtocol(name.as_ptr());
1053            proto.cast::<Self>().as_ref()
1054        }
1055    }
1056
1057    /// Obtains the list of registered protocol definitions.
1058    #[doc(alias = "objc_copyProtocolList")]
1059    pub fn protocols() -> MallocSlice!(&'static Self) {
1060        unsafe {
1061            let mut count: c_uint = 0;
1062            let protocols: *mut &Self = ffi::objc_copyProtocolList(&mut count).cast();
1063            MallocSlice::from_array(protocols, count as usize)
1064        }
1065    }
1066
1067    /// Get a list of the protocols to which this protocol conforms.
1068    #[doc(alias = "protocol_copyProtocolList")]
1069    pub fn adopted_protocols(&self) -> MallocSlice!(&AnyProtocol) {
1070        unsafe {
1071            let mut count: c_uint = 0;
1072            let protocols: *mut &AnyProtocol =
1073                ffi::protocol_copyProtocolList(self, &mut count).cast();
1074            MallocSlice::from_array(protocols, count as usize)
1075        }
1076    }
1077
1078    /// Checks whether this protocol conforms to the specified protocol.
1079    #[inline]
1080    #[doc(alias = "protocol_conformsToProtocol")]
1081    pub fn conforms_to(&self, proto: &AnyProtocol) -> bool {
1082        unsafe { ffi::protocol_conformsToProtocol(self, proto).as_bool() }
1083    }
1084
1085    /// Returns the name of self.
1086    #[inline]
1087    #[doc(alias = "protocol_getName")]
1088    pub fn name(&self) -> &CStr {
1089        unsafe { CStr::from_ptr(ffi::protocol_getName(self)) }
1090    }
1091
1092    fn method_descriptions_inner(&self, required: bool, instance: bool) -> Vec<MethodDescription> {
1093        let mut count: c_uint = 0;
1094        let descriptions = unsafe {
1095            ffi::protocol_copyMethodDescriptionList(
1096                self,
1097                Bool::new(required),
1098                Bool::new(instance),
1099                &mut count,
1100            )
1101        };
1102        if descriptions.is_null() {
1103            return Vec::new();
1104        }
1105        let descriptions = unsafe { MallocSlice::from_array(descriptions, count as usize) };
1106        descriptions
1107            .iter()
1108            .map(|desc| {
1109                unsafe { MethodDescription::from_raw(*desc) }.expect("invalid method description")
1110            })
1111            .collect()
1112    }
1113
1114    #[allow(dead_code)]
1115    #[doc(alias = "protocol_copyMethodDescriptionList")]
1116    pub(crate) fn method_descriptions(&self, required: bool) -> Vec<MethodDescription> {
1117        self.method_descriptions_inner(required, true)
1118    }
1119
1120    #[allow(dead_code)]
1121    #[doc(alias = "protocol_copyMethodDescriptionList")]
1122    pub(crate) fn class_method_descriptions(&self, required: bool) -> Vec<MethodDescription> {
1123        self.method_descriptions_inner(required, false)
1124    }
1125}
1126
1127impl PartialEq for AnyProtocol {
1128    /// Check whether the protocols are equal, or conform to each other.
1129    #[inline]
1130    #[doc(alias = "protocol_isEqual")]
1131    fn eq(&self, other: &Self) -> bool {
1132        unsafe { ffi::protocol_isEqual(self, other).as_bool() }
1133    }
1134}
1135
1136impl Eq for AnyProtocol {}
1137
1138// Don't implement `Hash` for protocol, it is unclear how that would work
1139
1140unsafe impl RefEncode for AnyProtocol {
1141    // Protocols are objects internally.
1142    const ENCODING_REF: Encoding = Encoding::Object;
1143}
1144
1145/// Note that protocols are objects, though sending messages to them is
1146/// officially deprecated.
1147//
1148// SAFETY: Protocols are NSObjects internally (and somewhat publicly, see e.g.
1149// `objc/Protocol.h`), and are returned as `Retained` in various places in
1150// Foundation. But that's considered deprecated, so we don't implement
1151// ClassType for them (even though the "Protocol" class exists).
1152unsafe impl Message for AnyProtocol {}
1153
1154impl fmt::Debug for AnyProtocol {
1155    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1156        f.debug_struct("AnyProtocol")
1157            .field("name", &self.name())
1158            .finish_non_exhaustive()
1159    }
1160}
1161
1162impl fmt::Display for AnyProtocol {
1163    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1164        // Protocols are usually UTF-8, so it's probably fine to do a lossy
1165        // conversion here.
1166        fmt::Display::fmt(&self.name().to_string_lossy(), f)
1167    }
1168}
1169
1170impl AsRef<Self> for AnyProtocol {
1171    fn as_ref(&self) -> &Self {
1172        self
1173    }
1174}
1175
1176impl AsRef<AnyObject> for AnyProtocol {
1177    fn as_ref(&self) -> &AnyObject {
1178        &self.inner
1179    }
1180}
1181
1182/// An Objective-C object.
1183///
1184/// This is slightly different from [`NSObject`] in that it may represent an
1185/// instance of an _arbitrary_ Objective-C class (e.g. it does not have to be
1186/// a subclass of `NSObject`, so it can represent other root classes like
1187/// `NSProxy`).
1188///
1189/// `Retained<AnyObject>` is equivalent to Objective-C's `id _Nonnull`.
1190///
1191/// This is an opaque type that contains [`UnsafeCell`], and is similar to
1192/// that in that one can safely access and perform interior mutability on this
1193/// (both via [`msg_send!`] and through ivars), so long as Rust's mutability
1194/// rules are upheld, and that data races are avoided.
1195///
1196/// Note: This is intentionally neither [`Sync`], [`Send`], [`UnwindSafe`],
1197/// [`RefUnwindSafe`] nor [`Unpin`], since that is something that may change
1198/// depending on the specific subclass. For example, `NSAutoreleasePool` is
1199/// not `Send`, it has to be deallocated on the same thread that it was
1200/// created. `NSLock` is not `Send` either.
1201///
1202/// [`UnsafeCell`]: core::cell::UnsafeCell
1203/// [`msg_send!`]: crate::msg_send
1204#[doc(alias = "id")]
1205#[doc(alias = "objc_object")]
1206#[repr(C)]
1207pub struct AnyObject {
1208    // `isa` field is deprecated, so we don't expose it here.
1209    //
1210    // Also, we need this to be a zero-sized, so that the compiler doesn't
1211    // assume anything about the layout.
1212    //
1213    // Use `object_getClass` instead.
1214    _priv: [u8; 0],
1215    _p: ffi::OpaqueData,
1216}
1217
1218/// Use [`AnyObject`] instead.
1219#[deprecated = "renamed to `runtime::AnyObject`. Consider using the correct type from the autogenerated `objc2-*` framework crates instead though"]
1220pub type Object = AnyObject;
1221
1222unsafe impl RefEncode for AnyObject {
1223    const ENCODING_REF: Encoding = Encoding::Object;
1224}
1225
1226// SAFETY: This is technically slightly wrong, not all objects implement the
1227// standard memory management methods. But not having this impl would be too
1228// restrictive, so we'll live with it.
1229//
1230// NOTE: AnyObject actually resolves to the class "Object" internally, but we
1231// don't want to expose that publicly, so we only implement Message here, not
1232// ClassType.
1233unsafe impl Message for AnyObject {}
1234
1235impl AnyObject {
1236    /// Dynamically find the class of this object.
1237    ///
1238    ///
1239    /// # Example
1240    ///
1241    /// Check that an instance of `NSObject` has the precise class `NSObject`.
1242    ///
1243    /// ```
1244    /// use objc2::ClassType;
1245    /// use objc2::runtime::NSObject;
1246    ///
1247    /// let obj = NSObject::new();
1248    /// assert_eq!(obj.class(), NSObject::class());
1249    /// ```
1250    #[inline]
1251    #[doc(alias = "object_getClass")]
1252    pub fn class(&self) -> &'static AnyClass {
1253        let ptr = unsafe { ffi::object_getClass(self) };
1254        // SAFETY: The class is not NULL because the object is not NULL, and
1255        // it is safe as `'static` since classes are static, and it could be
1256        // retrieved via `AnyClass::get(self.class().name())` anyhow.
1257        unsafe { ptr.as_ref().unwrap_unchecked() }
1258    }
1259
1260    /// Change the class of the object at runtime.
1261    ///
1262    /// Returns the object's previous class.
1263    ///
1264    ///
1265    /// # Safety
1266    ///
1267    /// The new class must:
1268    ///
1269    /// 1. Be a subclass of the object's current class.
1270    ///
1271    /// 2. The subclass must not add any instance variables - importantly, the
1272    ///    instance size of old and the new classes must be the same.
1273    ///
1274    /// 3. Any overridden methods on the new class must be fully compatible
1275    ///    with the old ones.
1276    ///
1277    /// Note that in the general case, where arbitrary parts of the program
1278    /// may be trying to modify the class of the object concurrently, these
1279    /// requirements are not actually possible to uphold.
1280    ///
1281    /// Since usage of this function is expected to be extremely rare, and
1282    /// even more so trying to do it concurrently, it is recommended that you
1283    /// verify that the returned class is what you would expect, and if not,
1284    /// panic.
1285    #[inline]
1286    #[doc(alias = "object_setClass")]
1287    pub unsafe fn set_class<'s>(this: &Self, cls: &AnyClass) -> &'s AnyClass {
1288        let this: *const Self = this;
1289        let this = this as *mut Self;
1290        let ptr = unsafe { ffi::object_setClass(this, cls) };
1291        // SAFETY: The class is not NULL because the object is not NULL.
1292        let old_cls = unsafe { ptr.as_ref().unwrap_unchecked() };
1293        // TODO: Check the superclass requirement too?
1294        debug_assert_eq!(
1295            old_cls.instance_size(),
1296            cls.instance_size(),
1297            "old and new class sizes were not equal; this is UB!"
1298        );
1299        old_cls
1300    }
1301
1302    /// Offset an object pointer to get a pointer to an ivar.
1303    ///
1304    ///
1305    /// # Safety
1306    ///
1307    /// The offset must be valid for the given type.
1308    #[inline]
1309    pub(crate) unsafe fn ivar_at_offset<T>(ptr: NonNull<Self>, offset: isize) -> NonNull<T> {
1310        // `offset` is given in bytes, so we convert to `u8` and back to `T`
1311        let ptr: NonNull<u8> = ptr.cast();
1312        let ptr: *mut u8 = ptr.as_ptr();
1313        // SAFETY: The offset is valid
1314        let ptr: *mut u8 = unsafe { ptr.offset(offset) };
1315        // SAFETY: The offset operation is guaranteed to not end up computing
1316        // a NULL pointer.
1317        let ptr: NonNull<u8> = unsafe { NonNull::new_unchecked(ptr) };
1318        let ptr: NonNull<T> = ptr.cast();
1319        ptr
1320    }
1321
1322    pub(crate) fn lookup_instance_variable_dynamically(&self, name: &str) -> &'static Ivar {
1323        let name = CString::new(name).unwrap();
1324        let cls = self.class();
1325        cls.instance_variable(&name)
1326            .unwrap_or_else(|| panic!("ivar {name:?} not found on class {cls}"))
1327    }
1328
1329    /// Use [`Ivar::load`] instead.
1330    ///
1331    ///
1332    /// # Safety
1333    ///
1334    /// The object must have an instance variable with the given name, and it
1335    /// must be of type `T`.
1336    ///
1337    /// See [`Ivar::load_ptr`] for details surrounding this.
1338    #[deprecated = "this is difficult to use correctly, use `Ivar::load` instead."]
1339    pub unsafe fn get_ivar<T: Encode>(&self, name: &str) -> &T {
1340        let ivar = self.lookup_instance_variable_dynamically(name);
1341        // SAFETY: Upheld by caller
1342        unsafe { ivar.load::<T>(self) }
1343    }
1344
1345    /// Use [`Ivar::load_mut`] instead.
1346    ///
1347    ///
1348    /// # Safety
1349    ///
1350    /// The object must have an instance variable with the given name, and it
1351    /// must be of type `T`.
1352    ///
1353    /// See [`Ivar::load_ptr`] for details surrounding this.
1354    #[deprecated = "this is difficult to use correctly, use `Ivar::load_mut` instead."]
1355    pub unsafe fn get_mut_ivar<T: Encode>(&mut self, name: &str) -> &mut T {
1356        let ivar = self.lookup_instance_variable_dynamically(name);
1357        // SAFETY: Upheld by caller
1358        unsafe { ivar.load_mut::<T>(self) }
1359    }
1360
1361    pub(crate) fn is_kind_of_class(&self, cls: &AnyClass) -> Bool {
1362        // SAFETY: The signature is correct.
1363        //
1364        // Note that `isKindOfClass:` is not available on every object, but it
1365        // is still safe to _use_, since the runtime will simply crash if the
1366        // selector isn't implemented. This is of course not _ideal_, but it
1367        // works for all of Apple's Objective-C classes, and it's what Swift
1368        // does.
1369        //
1370        // In theory, someone could have made a root object, and overwritten
1371        // `isKindOfClass:` to do something bogus - but that would conflict
1372        // with normal Objective-C code as well, so we will consider such a
1373        // thing unsound by construction.
1374        unsafe { msg_send![self, isKindOfClass: cls] }
1375    }
1376
1377    /// Attempt to downcast the object to a class of type `T`.
1378    ///
1379    /// This is the reference-variant. Use [`Retained::downcast`] if you want
1380    /// to convert a retained object to another type.
1381    ///
1382    /// [`Retained::downcast`]: crate::rc::Retained::downcast
1383    ///
1384    ///
1385    /// # Mutable classes
1386    ///
1387    /// Some classes have immutable and mutable variants, such as `NSString`
1388    /// and `NSMutableString`.
1389    ///
1390    /// When some Objective-C API signature says it gives you an immutable
1391    /// class, it generally expects you to not mutate that, even though it may
1392    /// technically be mutable "under the hood".
1393    ///
1394    /// So using this method to convert a `NSString` to a `NSMutableString`,
1395    /// while not unsound, is generally frowned upon unless you created the
1396    /// string yourself, or the API explicitly documents the string to be
1397    /// mutable.
1398    ///
1399    /// See Apple's [documentation on mutability][apple-mut] and [on
1400    /// `isKindOfClass:`][iskindof-doc] for more details.
1401    ///
1402    /// [iskindof-doc]: https://developer.apple.com/documentation/objectivec/1418956-nsobject/1418511-iskindofclass?language=objc
1403    /// [apple-mut]: https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaEncyclopedia/ObjectMutability/ObjectMutability.html
1404    ///
1405    ///
1406    /// # Generic classes
1407    ///
1408    /// Objective-C generics are called "lightweight generics", and that's
1409    /// because they aren't exposed in the runtime. This makes it impossible
1410    /// to safely downcast to generic collections, so this is disallowed by
1411    /// this method.
1412    ///
1413    /// You can, however, safely downcast to generic collections where all the
1414    /// type-parameters are [`AnyObject`].
1415    ///
1416    ///
1417    /// # Panics
1418    ///
1419    /// This works internally by calling `isKindOfClass:`. That means that the
1420    /// object must have the instance method of that name, and an exception
1421    /// will be thrown (if CoreFoundation is linked) or the process will abort
1422    /// if that is not the case. In the vast majority of cases, you don't need
1423    /// to worry about this, since both root objects [`NSObject`] and
1424    /// `NSProxy` implement this method.
1425    ///
1426    ///
1427    /// # Examples
1428    ///
1429    /// Cast an `NSString` back and forth from `NSObject`.
1430    ///
1431    /// ```
1432    /// use objc2::rc::Retained;
1433    /// use objc2_foundation::{NSObject, NSString};
1434    ///
1435    /// let obj: Retained<NSObject> = NSString::new().into_super();
1436    /// let string = obj.downcast_ref::<NSString>().unwrap();
1437    /// // Or with `downcast`, if we do not need the object afterwards
1438    /// let string = obj.downcast::<NSString>().unwrap();
1439    /// ```
1440    ///
1441    /// Try (and fail) to cast an `NSObject` to an `NSString`.
1442    ///
1443    /// ```
1444    /// use objc2_foundation::{NSObject, NSString};
1445    ///
1446    /// let obj = NSObject::new();
1447    /// assert!(obj.downcast_ref::<NSString>().is_none());
1448    /// ```
1449    ///
1450    /// Try to cast to an array of strings.
1451    ///
1452    /// ```compile_fail,E0277
1453    /// use objc2_foundation::{NSArray, NSObject, NSString};
1454    ///
1455    /// let arr = NSArray::from_retained_slice(&[NSObject::new()]);
1456    /// // This is invalid and doesn't type check.
1457    /// let arr = arr.downcast_ref::<NSArray<NSString>>();
1458    /// ```
1459    ///
1460    /// This fails to compile, since it would require enumerating over the
1461    /// array to ensure that each element is of the desired type, which is a
1462    /// performance pitfall.
1463    ///
1464    /// Downcast when processing each element instead.
1465    ///
1466    /// ```
1467    /// use objc2_foundation::{NSArray, NSObject, NSString};
1468    ///
1469    /// let arr = NSArray::from_retained_slice(&[NSObject::new()]);
1470    ///
1471    /// for elem in arr {
1472    ///     if let Some(data) = elem.downcast_ref::<NSString>() {
1473    ///         // handle `data`
1474    ///     }
1475    /// }
1476    /// ```
1477    #[inline]
1478    pub fn downcast_ref<T: DowncastTarget>(&self) -> Option<&T> {
1479        if self.is_kind_of_class(T::class()).as_bool() {
1480            // SAFETY: Just checked that the object is a class of type `T`.
1481            //
1482            // Generic `T` like `NSArray<NSString>` are ruled out by
1483            // `T: DowncastTarget`.
1484            Some(unsafe { &*(self as *const Self).cast::<T>() })
1485        } else {
1486            None
1487        }
1488    }
1489
1490    // objc_setAssociatedObject
1491    // objc_getAssociatedObject
1492    // objc_removeAssociatedObjects
1493}
1494
1495impl fmt::Debug for AnyObject {
1496    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1497        let ptr: *const Self = self;
1498        write!(f, "<{}: {:p}>", self.class(), ptr)
1499    }
1500}
1501
1502#[cfg(test)]
1503mod tests {
1504    use alloc::ffi::CString;
1505    use alloc::format;
1506    use alloc::string::ToString;
1507    use core::mem::size_of;
1508
1509    use super::*;
1510    use crate::test_utils;
1511    use crate::{class, msg_send, sel, ClassType, ProtocolType};
1512
1513    // TODO: Remove once c"" strings are in MSRV
1514    fn c(s: &str) -> CString {
1515        CString::new(s).unwrap()
1516    }
1517
1518    #[test]
1519    fn test_selector() {
1520        macro_rules! test_sel {
1521            ($s:literal, $($tt:tt)+) => {{
1522                let sel = sel!($($tt)*);
1523                let expected = Sel::register(&c($s));
1524                assert_eq!(sel, expected);
1525                assert_eq!(sel.name().to_str(), Ok($s));
1526            }}
1527        }
1528        test_sel!("abc", abc);
1529        test_sel!("abc:", abc:);
1530        test_sel!("abc:def:", abc:def:);
1531        test_sel!("abc:def:ghi:", abc:def:ghi:);
1532        test_sel!("functionWithControlPoints::::", functionWithControlPoints::::);
1533        test_sel!("initWithControlPoints::::", initWithControlPoints::::);
1534        test_sel!("setFloatValue::", setFloatValue::);
1535        test_sel!("isSupported::", isSupported::);
1536        test_sel!("addEventListener:::", addEventListener:::);
1537        test_sel!("test::arg::", test::arg::);
1538        test_sel!("test::::with::spaces::", test : :: : with : : spaces : :);
1539        test_sel!("a::b:", a::b:);
1540    }
1541
1542    #[test]
1543    fn test_empty_selector() {
1544        let s = c("");
1545        let sel = Sel::register(&s);
1546        assert_eq!(sel.name(), &*s);
1547        let s = c(":");
1548        let sel = Sel::register(&s);
1549        assert_eq!(sel.name(), &*s);
1550        let s = c("::");
1551        let sel = Sel::register(&s);
1552        assert_eq!(sel.name(), &*s);
1553    }
1554
1555    #[test]
1556    fn test_ivar() {
1557        let cls = test_utils::custom_class();
1558        let ivar = cls.instance_variable(&c("_foo")).unwrap();
1559        assert_eq!(ivar.name(), &*c("_foo"));
1560        assert!(<u32>::ENCODING.equivalent_to_str(ivar.type_encoding().to_str().unwrap()));
1561        assert!(ivar.offset() > 0);
1562        assert!(cls.instance_variables().len() > 0);
1563    }
1564
1565    #[test]
1566    fn test_instance_method() {
1567        let cls = test_utils::custom_class();
1568        let sel = Sel::register(&c("foo"));
1569        let method = cls.instance_method(sel).unwrap();
1570        assert_eq!(method.name().name(), &*c("foo"));
1571        assert_eq!(method.arguments_count(), 2);
1572
1573        assert!(<u32>::ENCODING.equivalent_to_str(method.return_type().to_str().unwrap()));
1574        assert!(Sel::ENCODING.equivalent_to_str(method.argument_type(1).unwrap().to_str().unwrap()));
1575
1576        assert!(cls.instance_methods().iter().any(|m| *m == method));
1577    }
1578
1579    #[test]
1580    fn test_class_method() {
1581        let cls = test_utils::custom_class();
1582        let method = cls.class_method(sel!(classFoo)).unwrap();
1583        assert_eq!(method.name().name(), &*c("classFoo"));
1584        assert_eq!(method.arguments_count(), 2);
1585
1586        assert!(<u32>::ENCODING.equivalent_to_str(method.return_type().to_str().unwrap()));
1587        assert!(Sel::ENCODING.equivalent_to_str(method.argument_type(1).unwrap().to_str().unwrap()));
1588
1589        assert!(cls
1590            .metaclass()
1591            .instance_methods()
1592            .iter()
1593            .any(|m| *m == method));
1594    }
1595
1596    #[test]
1597    fn test_class() {
1598        let cls = test_utils::custom_class();
1599        assert_eq!(cls.name(), &*c("CustomObject"));
1600        assert!(cls.instance_size() > 0);
1601        assert!(cls.superclass().is_none());
1602
1603        assert!(cls.responds_to(sel!(foo)));
1604        assert!(cls.responds_to(sel!(setBar:)));
1605        assert!(cls.responds_to(sel!(test::test::)));
1606        assert!(!cls.responds_to(sel!(abc)));
1607        assert!(!cls.responds_to(sel!(addNumber:toNumber:)));
1608
1609        assert_eq!(AnyClass::get(cls.name()), Some(cls));
1610
1611        let metaclass = cls.metaclass();
1612        // The metaclass of a root class is a subclass of the root class
1613        assert_eq!(metaclass.superclass().unwrap(), cls);
1614        assert!(metaclass.responds_to(sel!(addNumber:toNumber:)));
1615        assert!(metaclass.responds_to(sel!(test::test::)));
1616        // TODO: This is unexpected!
1617        assert!(metaclass.responds_to(sel!(foo)));
1618
1619        let subclass = test_utils::custom_subclass();
1620        assert_eq!(subclass.superclass().unwrap(), cls);
1621    }
1622
1623    #[test]
1624    fn test_classes_count() {
1625        assert!(AnyClass::classes_count() > 0);
1626    }
1627
1628    #[test]
1629    fn test_classes() {
1630        let classes = AnyClass::classes();
1631        assert!(classes.len() > 0);
1632    }
1633
1634    #[test]
1635    fn test_protocol() {
1636        let proto = test_utils::custom_protocol();
1637        assert_eq!(proto.name(), &*c("CustomProtocol"));
1638        let class = test_utils::custom_class();
1639        assert!(class.conforms_to(proto));
1640
1641        // The selectors are broken somehow on GNUStep < 2.0
1642        if cfg!(any(not(feature = "gnustep-1-7"), feature = "gnustep-2-0")) {
1643            let desc = MethodDescription {
1644                sel: sel!(setBar:),
1645                types: CStr::from_bytes_with_nul(b"v@:i\0").unwrap(),
1646            };
1647            assert_eq!(&proto.method_descriptions(true), &[desc]);
1648            let desc = MethodDescription {
1649                sel: sel!(getName),
1650                types: CStr::from_bytes_with_nul(b"*@:\0").unwrap(),
1651            };
1652            assert_eq!(&proto.method_descriptions(false), &[desc]);
1653            let desc = MethodDescription {
1654                sel: sel!(addNumber:toNumber:),
1655                types: CStr::from_bytes_with_nul(b"i@:ii\0").unwrap(),
1656            };
1657            assert_eq!(&proto.class_method_descriptions(true), &[desc]);
1658        }
1659        assert_eq!(&proto.class_method_descriptions(false), &[]);
1660
1661        assert!(class.adopted_protocols().iter().any(|p| *p == proto));
1662    }
1663
1664    #[test]
1665    fn test_protocol_method() {
1666        let class = test_utils::custom_class();
1667        let result: i32 = unsafe { msg_send![class, addNumber: 1, toNumber: 2] };
1668        assert_eq!(result, 3);
1669    }
1670
1671    #[test]
1672    fn class_self() {
1673        let cls = NSObject::class();
1674        let result: &'static AnyClass = unsafe { msg_send![cls, self] };
1675        assert_eq!(cls, result);
1676    }
1677
1678    #[test]
1679    fn test_subprotocols() {
1680        let sub_proto = test_utils::custom_subprotocol();
1681        let super_proto = test_utils::custom_protocol();
1682        assert!(sub_proto.conforms_to(super_proto));
1683        assert_eq!(sub_proto.adopted_protocols()[0], super_proto);
1684    }
1685
1686    #[test]
1687    fn test_protocols() {
1688        // Ensure that a protocol has been registered on linux
1689        let _ = test_utils::custom_protocol();
1690
1691        assert!(AnyProtocol::protocols().len() > 0);
1692    }
1693
1694    #[test]
1695    fn test_object() {
1696        let obj = test_utils::custom_object();
1697        let cls = test_utils::custom_class();
1698        assert_eq!(obj.class(), cls);
1699
1700        let ivar = cls.instance_variable(&c("_foo")).unwrap();
1701
1702        unsafe { *ivar.load_ptr::<u32>(&obj) = 4 };
1703        let result = unsafe { *ivar.load::<u32>(&obj) };
1704        assert_eq!(result, 4);
1705    }
1706
1707    #[test]
1708    fn test_object_ivar_unknown() {
1709        let cls = test_utils::custom_class();
1710        assert_eq!(cls.instance_variable(&c("unknown")), None);
1711    }
1712
1713    #[test]
1714    fn test_no_ivars() {
1715        let cls = ClassBuilder::new(&c("NoIvarObject"), NSObject::class())
1716            .unwrap()
1717            .register();
1718        assert_eq!(cls.instance_variables().len(), 0);
1719    }
1720
1721    #[test]
1722    #[cfg_attr(
1723        all(debug_assertions, not(feature = "disable-encoding-assertions")),
1724        should_panic = "wrong encoding. Tried to retrieve ivar with encoding I, but the encoding of the given type was C"
1725    )]
1726    fn test_object_ivar_wrong_type() {
1727        let obj = test_utils::custom_object();
1728        let cls = test_utils::custom_class();
1729        let ivar = cls.instance_variable(&c("_foo")).unwrap();
1730        let _ = unsafe { *ivar.load::<u8>(&obj) };
1731    }
1732
1733    #[test]
1734    fn test_encode() {
1735        fn assert_enc<T: Encode>(expected: &str) {
1736            assert_eq!(&T::ENCODING.to_string(), expected);
1737        }
1738        assert_enc::<&AnyObject>("@");
1739        assert_enc::<*mut AnyObject>("@");
1740        assert_enc::<&AnyClass>("#");
1741        assert_enc::<Sel>(":");
1742        assert_enc::<Option<Sel>>(":");
1743        assert_enc::<Imp>("^?");
1744        assert_enc::<Option<Imp>>("^?");
1745        assert_enc::<&AnyProtocol>("@");
1746    }
1747
1748    #[test]
1749    fn test_send_sync() {
1750        fn assert_send_sync<T: Send + Sync + ?Sized>() {}
1751        assert_send_sync::<Bool>();
1752        assert_send_sync::<AnyClass>();
1753        assert_send_sync::<Ivar>();
1754        assert_send_sync::<Method>();
1755        assert_send_sync::<AnyProtocol>();
1756        assert_send_sync::<Sel>();
1757    }
1758
1759    #[test]
1760    fn test_debug_display() {
1761        let sel = sel!(abc:);
1762        assert_eq!(format!("{sel}"), "abc:");
1763        assert_eq!(format!("{sel:?}"), "Sel(\"abc:\")");
1764        let cls = test_utils::custom_class();
1765        assert_eq!(format!("{cls}"), "CustomObject");
1766        assert_eq!(
1767            format!("{cls:?}"),
1768            "AnyClass { name: \"CustomObject\", .. }"
1769        );
1770        let protocol = test_utils::custom_protocol();
1771        assert_eq!(format!("{protocol}"), "CustomProtocol");
1772        assert_eq!(
1773            format!("{protocol:?}"),
1774            "AnyProtocol { name: \"CustomProtocol\", .. }"
1775        );
1776
1777        let object = test_utils::custom_object();
1778        assert_eq!(
1779            format!("{:?}", &*object),
1780            format!("CustomObject(<CustomObject: {:p}>)", &*object)
1781        );
1782    }
1783
1784    #[test]
1785    fn test_multiple_colon() {
1786        let class = test_utils::custom_class();
1787        let res: i32 = unsafe {
1788            MessageReceiver::send_message(class, sel!(test::test::), (1i32, 2i32, 3i32, 4i32))
1789        };
1790        assert_eq!(res, 10);
1791
1792        let obj = test_utils::custom_object();
1793        let res: i32 = unsafe {
1794            MessageReceiver::send_message(&*obj, sel!(test::test::), (1i32, 2i32, 3i32, 4i32))
1795        };
1796        assert_eq!(res, 24);
1797    }
1798
1799    #[test]
1800    fn test_sizes() {
1801        assert_eq!(size_of::<Sel>(), size_of::<*const ()>());
1802        assert_eq!(size_of::<Sel>(), size_of::<Option<Sel>>());
1803
1804        // These must be zero-sized until we get extern types, otherwise the
1805        // optimizer may invalidly assume something about their layout.
1806        assert_eq!(size_of::<AnyClass>(), 0);
1807        assert_eq!(size_of::<AnyObject>(), 0);
1808        assert_eq!(size_of::<AnyProtocol>(), 0);
1809        assert_eq!(size_of::<Ivar>(), 0);
1810        assert_eq!(size_of::<Method>(), 0);
1811    }
1812
1813    fn get_ivar_layout(cls: &AnyClass) -> *const u8 {
1814        unsafe { ffi::class_getIvarLayout(cls) }
1815    }
1816
1817    #[test]
1818    #[cfg_attr(
1819        feature = "gnustep-1-7",
1820        ignore = "ivar layout is still used on GNUStep"
1821    )]
1822    fn test_layout_does_not_matter_any_longer() {
1823        assert!(get_ivar_layout(class!(NSObject)).is_null());
1824        assert!(get_ivar_layout(class!(NSArray)).is_null());
1825        assert!(get_ivar_layout(class!(NSException)).is_null());
1826        assert!(get_ivar_layout(class!(NSNumber)).is_null());
1827        assert!(get_ivar_layout(class!(NSString)).is_null());
1828    }
1829
1830    #[test]
1831    fn test_non_utf8_roundtrip() {
1832        // Some invalid UTF-8 character
1833        let s = CStr::from_bytes_with_nul(b"\x9F\0").unwrap();
1834
1835        let sel = Sel::register(s);
1836        assert_eq!(sel.name(), s);
1837        assert_eq!(sel.to_string(), char::REPLACEMENT_CHARACTER.to_string());
1838
1839        let cls = ClassBuilder::new(s, NSObject::class()).unwrap().register();
1840        assert_eq!(cls.name(), s);
1841        assert_eq!(cls.to_string(), char::REPLACEMENT_CHARACTER.to_string());
1842
1843        let cls_runtime = AnyClass::get(s).unwrap();
1844        assert_eq!(cls, cls_runtime);
1845    }
1846
1847    #[test]
1848    fn class_is_object() {
1849        let cls = NSObject::class();
1850        let retained = cls.retain();
1851        assert_eq!(&*retained, cls);
1852
1853        let obj: &AnyObject = cls.as_ref();
1854        let superclass = obj.class();
1855        assert!(superclass.conforms_to(<dyn NSObjectProtocol>::protocol().unwrap()));
1856
1857        // Classes are NSObject subclasses in the current runtime.
1858        let ns_obj = retained.downcast::<NSObject>().unwrap();
1859        // Test that we can call NSObject methods on classes.
1860        assert_eq!(ns_obj, ns_obj);
1861        let _ = ns_obj.retainCount();
1862    }
1863
1864    #[test]
1865    fn class_has_infinite_retain_count() {
1866        let obj: &AnyObject = NSObject::class().as_ref();
1867        let obj = obj.downcast_ref::<NSObject>().unwrap();
1868
1869        let large_retain = if cfg!(feature = "gnustep-1-7") {
1870            u32::MAX as usize
1871        } else {
1872            usize::MAX
1873        };
1874
1875        assert_eq!(obj.retainCount(), large_retain);
1876        let obj2 = obj.retain();
1877        assert_eq!(obj.retainCount(), large_retain);
1878        drop(obj2);
1879        assert_eq!(obj.retainCount(), large_retain);
1880    }
1881
1882    #[test]
1883    fn protocol_is_object() {
1884        let protocol = <dyn NSObjectProtocol>::protocol().unwrap();
1885        let retained = protocol.retain();
1886        assert_eq!(&*retained, protocol);
1887
1888        // Protocols don't implement isKindOfClass: on GNUStep.
1889        if cfg!(feature = "gnustep-1-7") {
1890            return;
1891        }
1892
1893        // In the old runtime, NSObjectProtocol are not NSObject subclasses.
1894        if cfg!(all(target_os = "macos", target_arch = "x86")) {
1895            let _ = retained.downcast::<NSObject>().unwrap_err();
1896        } else {
1897            // But elsewhere they are.
1898            let obj = retained.downcast::<NSObject>().unwrap();
1899            // Test that we can call NSObject methods on protocols.
1900            assert_eq!(obj, obj);
1901            let _ = obj.retainCount();
1902        }
1903    }
1904}