/// Wrap the given closure in `exception::catch` if the `catch-all` feature is /// enabled. /// /// This is a macro to help with monomorphization when the feature is /// disabled, as well as improving the final stack trace (`#[track_caller]` /// doesn't really work on closures). #[cfg(not(feature = "catch-all"))]
macro_rules! conditional_try {
(|| $expr:expr) => {
$expr
};
}
/// On the below architectures we can statically find the correct method to /// call from the return type, by looking at its `EncodeReturn` impl. #[allow(clippy::missing_safety_doc)] unsafetrait MsgSendFn: EncodeReturn { const MSG_SEND: Imp; const MSG_SEND_SUPER: Imp;
}
#[cfg(target_arch = "aarch64")] /// `objc_msgSend_stret` is not even available in arm64. /// /// <https://twitter.com/gparker/status/378079715824660480> unsafeimpl<T: EncodeReturn> MsgSendFn for T { const MSG_SEND: Imp = ffi::objc_msgSend; const MSG_SEND_SUPER: Imp = ffi::objc_msgSendSuper;
}
#[cfg(target_arch = "x86_64")] /// If the size of an object is larger than two eightbytes, it has class /// MEMORY. If the type has class MEMORY, then the caller provides space for /// the return value and passes the address of this storage. /// /// <https://www.uclibc.org/docs/psABI-x86_64.pdf> /// <https://github.com/llvm/llvm-project/blob/llvmorg-17.0.6/clang/lib/CodeGen/Targets/X86.cpp#L2532> unsafeimpl<T: EncodeReturn> MsgSendFn for T { const MSG_SEND: Imp = { // See https://github.com/apple-oss-distributions/objc4/blob/objc4-818.2/runtime/message.h#L156-L172 iflet Encoding::LongDouble = T::ENCODING_RETURN {
ffi::objc_msgSend_fpret
} elseiflet Encoding::LongDoubleComplex = T::ENCODING_RETURN {
ffi::objc_msgSend_fp2ret
} elseif mem::size_of::<T>() <= 16 {
ffi::objc_msgSend
} else {
ffi::objc_msgSend_stret
}
}; const MSG_SEND_SUPER: Imp = { if mem::size_of::<T>() <= 16 {
ffi::objc_msgSendSuper
} else {
ffi::objc_msgSendSuper_stret
}
};
}
#[inline] #[track_caller] pub(crate) unsafefn send<A: EncodeArguments, R: EncodeReturn>(
receiver: *mut AnyObject,
sel: Sel,
args: A,
) -> R { let msg_send_fn = R::MSG_SEND; // Note: Modern Objective-C compilers have a workaround to ensure that // messages to `nil` with a struct return produces `mem::zeroed()`, // see: // <https://www.sealiesoftware.com/blog/archive/2012/2/29/objc_explain_return_value_of_message_to_nil.html> // // We _could_ technically do something similar, but since we're // disallowing messages to `nil` with `debug_assertions` enabled // anyhow, and since Rust has a much stronger type-system that // disallows NULL/nil in most cases, we won't bother supporting it. unsafe { A::__invoke(msg_send_fn, receiver, sel, args) }
}
#[inline] #[track_caller] pub(crate) unsafefn send_super<A: EncodeArguments, R: EncodeReturn>(
receiver: *mut AnyObject,
super_class: &AnyClass,
sel: Sel,
args: A,
) -> R { letmut sup = ffi::objc_super {
receiver,
super_class,
}; let receiver: *mut ffi::objc_super = &mut sup; let receiver = receiver.cast();
#[inline] fn unwrap_msg_send_fn(msg_send_fn: Option<Imp>) -> Imp { match msg_send_fn {
Some(msg_send_fn) => msg_send_fn,
None => { // SAFETY: This will never be NULL, even if the selector is not // found a callable function pointer will still be returned! // // `clang` doesn't insert a NULL check here either. unsafe { core::hint::unreachable_unchecked() }
}
}
}
#[track_caller] pub(crate) unsafefn send<A: EncodeArguments, R: EncodeReturn>(
receiver: *mut AnyObject,
sel: Sel,
args: A,
) -> R { // If `receiver` is NULL, objc_msg_lookup will return a standard // C-method taking two arguments, the receiver and the selector. // // Transmuting and calling such a function with multiple parameters is // safe as long as the return value is a primitive (and e.g. not a big // struct or array). // // However, when the return value is a floating point value, the float // will end up as some undefined value, usually NaN, which is // incompatible with Apple's platforms. As such, we insert this extra // NULL check here. if receiver.is_null() { // SAFETY: Caller guarantees that messages to NULL-receivers only // return pointers or primitive values, and a mem::zeroed pointer // / primitive is just a NULL-pointer or a zeroed primitive. returnunsafe { mem::zeroed() };
}
let msg_send_fn = unsafe { ffi::objc_msg_lookup(receiver, sel) }; let msg_send_fn = unwrap_msg_send_fn(msg_send_fn); unsafe { A::__invoke(msg_send_fn, receiver, sel, args) }
}
#[track_caller] pub(crate) unsafefn send_super<A: EncodeArguments, R: EncodeReturn>(
receiver: *mut AnyObject,
super_class: &AnyClass,
sel: Sel,
args: A,
) -> R { if receiver.is_null() { // SAFETY: Same as in `send`. returnunsafe { mem::zeroed() };
}
let sup = ffi::objc_super {
receiver,
super_class,
}; let msg_send_fn = unsafe { ffi::objc_msg_lookup_super(&sup, sel) }; let msg_send_fn = unwrap_msg_send_fn(msg_send_fn); unsafe { A::__invoke(msg_send_fn, receiver, sel, args) }
}
}
/// Types that can directly be used as the receiver of Objective-C messages. /// /// Examples include objects pointers, class pointers, and block pointers. /// /// /// # Safety /// /// This is a sealed trait, and should not need to be implemented. Open an /// issue if you know a use-case where this restrition should be lifted! pubunsafetrait MessageReceiver: private::Sealed + Sized { #[doc(hidden)] type __Inner: ?Sized + RefEncode;
/// Sends a message to the receiver with the given selector and arguments. /// /// This should be used instead of the [`performSelector:`] family of /// methods, as this is both more performant and flexible than that. /// /// The correct version of `objc_msgSend` will be chosen based on the /// return type. For more information, see [the Messaging section in /// Apple's Objective-C Runtime Programming Guide][guide-messaging]. /// /// If the selector is known at compile-time, it is recommended to use the /// [`msg_send!`] macro rather than this method. /// /// [`performSelector:`]: https://developer.apple.com/documentation/objectivec/1418956-nsobject/1418867-performselector?language=objc /// [guide-messaging]: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtHowMessagingWorks.html /// /// /// # Safety /// /// This shares the same safety requirements as [`msg_send!`]. /// /// The added invariant is that the selector must take the same number of /// arguments as is given. /// /// [`msg_send!`]: crate::msg_send /// /// /// # Example /// /// Call the `copy` method, but using a dynamic selector instead. /// /// ```no_run /// use objc2::rc::Retained; /// use objc2::runtime::MessageReceiver; /// use objc2::sel; /// # use objc2::runtime::NSObject as MyObject; /// /// let obj = MyObject::new(); /// // SAFETY: The `copy` method takes no arguments, and returns an object /// let copy: *mut MyObject = unsafe { obj.send_message(sel!(copy), ()) }; /// // SAFETY: The `copy` method returns an object with +1 retain count /// let copy = unsafe { Retained::from_raw(copy) }.unwrap(); /// ``` #[inline] #[track_caller] #[doc(alias = "performSelector")] #[doc(alias = "performSelector:")] #[doc(alias = "performSelector:withObject:")] #[doc(alias = "performSelector:withObject:withObject:")] unsafefn send_message<A: EncodeArguments, R: EncodeReturn>(self, sel: Sel, args: A) -> R { let receiver = self.__as_raw_receiver(); #[cfg(debug_assertions)]
{ // SAFETY: Caller ensures only valid or NULL pointers. let obj = unsafe { receiver.as_ref() };
msg_send_check(obj, sel, A::ENCODINGS, &R::ENCODING_RETURN);
}
/// Sends a message to a specific superclass with the given selector and /// arguments. /// /// The correct version of `objc_msgSend_super` will be chosen based on the /// return type. For more information, see the section on "Sending /// Messages" in Apple's [documentation][runtime]. /// /// If the selector is known at compile-time, it is recommended to use the /// [`msg_send!(super(...), ...)`] macro rather than this method. /// /// [runtime]: https://developer.apple.com/documentation/objectivec/objective-c_runtime?language=objc /// /// /// # Safety /// /// This shares the same safety requirements as /// [`msg_send!(super(...), ...)`]. /// /// The added invariant is that the selector must take the same number of /// arguments as is given. /// /// [`msg_send!(super(...), ...)`]: crate::msg_send #[inline] #[track_caller] unsafefn send_super_message<A: EncodeArguments, R: EncodeReturn>( self,
superclass: &AnyClass,
sel: Sel,
args: A,
) -> R { let receiver = self.__as_raw_receiver(); #[cfg(debug_assertions)]
{ if receiver.is_null() {
panic_null(sel);
}
msg_send_check_class(superclass, sel, A::ENCODINGS, &R::ENCODING_RETURN);
}
// Note that we implement MessageReceiver for unsized types as well, this is // to support `extern type`s in the future, not because we want to allow DSTs.
impl<T: ?Sized + Message> private::Sealed for *const T {} unsafeimpl<T: ?Sized + Message> MessageReceiver for *const T { type __Inner = T;
impl<T: ?Sized + Message> private::Sealed for &T {} unsafeimpl<T: ?Sized + Message> MessageReceiver for &T { type __Inner = T;
#[inline] fn __as_raw_receiver(self) -> *mut AnyObject { let ptr: *const T = self;
(ptr as *mut T).cast()
}
}
impl private::Sealed for &mut AnyObject {} /// `&mut AnyObject` is allowed as mutable, for easier transition from `objc`, /// even though it's basically always incorrect to hold `&mut AnyObject`. /// /// Use `*mut AnyObject` instead if you know for certain you need mutability, /// and cannot make do with interior mutability. unsafeimpl MessageReceiver for &mut AnyObject { type __Inner = AnyObject;
#[allow(unused)] fn test_different_receivers(obj: &mut AnyObject) { unsafe { let x = &mut *obj; let _: () = msg_send![x, mutable1]; // `x` is consumed by the above, so this won't work: // let _: () = msg_send![x, mutable2];
// It is only possible if we reborrow: let _: () = msg_send![&mut *obj, mutable1]; let _: () = msg_send![&mut *obj, mutable2];
// Test NonNull let obj = NonNull::from(obj); let _: () = msg_send![obj, mutable1]; let _: () = msg_send![obj, mutable2];
// And test raw pointers let obj: *mut AnyObject = obj.as_ptr(); let _: () = msg_send![obj, mutable1]; let _: () = msg_send![obj, mutable2];
}
}
#[test] fn test_send_message() { let obj = test_utils::custom_object(); let _: () = unsafe { msg_send![&obj, setFoo: 4u32] }; let result: u32 = unsafe { msg_send![&obj, foo] };
assert_eq!(result, 4);
}
#[test] #[cfg_attr(debug_assertions, should_panic = "messsaging description to nil")] fn test_send_message_nil() { let nil: *mut NSObject = ::core::ptr::null_mut();
// This result should not be relied on let result: Option<Retained<NSObject>> = unsafe { msg_send![nil, description] };
assert!(result.is_none());
// This result should not be relied on let result: usize = unsafe { msg_send![nil, hash] };
assert_eq!(result, 0);
// This result should not be relied on #[cfg(target_pointer_width = "16")] let result: f32 = 0.0; #[cfg(target_pointer_width = "32")] let result: f32 = unsafe { msg_send![nil, floatValue] }; #[cfg(target_pointer_width = "64")] let result: f64 = unsafe { msg_send![nil, doubleValue] };
assert_eq!(result, 0.0);
// This result should not be relied on let result: Option<Retained<NSObject>> = unsafe { msg_send![nil, multiple: 1u32, arguments: 2i8] };
assert!(result.is_none());
// This result should not be relied on let obj = unsafe { Allocated::new(ptr::null_mut()) }; let result: Option<Retained<NSObject>> = unsafe { msg_send![obj, init] };
assert!(result.is_none());
}
#[test] fn test_send_message_super() { let obj = test_utils::custom_subclass_object(); let superclass = test_utils::custom_class(); unsafe { let _: () = msg_send![&obj, setFoo: 4u32]; let foo: u32 = msg_send![super(&obj, superclass), foo];
assert_eq!(foo, 4);
// The subclass is overridden to return foo + 2 let foo: u32 = msg_send![&obj, foo];
assert_eq!(foo, 6);
}
}
#[test] #[cfg_attr(
feature = "gnustep-1-7",
ignore = "GNUStep deadlocks here for some reason"
)] fn test_send_message_class_super() { let cls = test_utils::custom_subclass(); let superclass = test_utils::custom_class(); unsafe { let foo: u32 = msg_send![super(cls, superclass.metaclass()), classFoo];
assert_eq!(foo, 7);
// The subclass is overridden to return + 2 let foo: u32 = msg_send![cls, classFoo];
assert_eq!(foo, 9);
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.30 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.