1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
/// Gets a reference to a [`Class`] from the given name.
///
/// # Panics
///
/// Panics if no class with the given name can be found.
///
/// To check for a class that may not exist, use [`Class::get`].
///
/// [`Class`]: crate::runtime::Class
/// [`Class::get`]: crate::runtime::Class::get
///
/// # Examples
///
/// ```no_run
/// # use objc2::class;
/// let cls = class!(NSObject);
/// ```
#[macro_export]
macro_rules! class {
($name:ident) => {{
static CLASS: $crate::__CachedClass = $crate::__CachedClass::new();
let name = concat!(stringify!($name), '\0');
#[allow(unused_unsafe)]
let cls = unsafe { CLASS.get(name) };
match cls {
Some(cls) => cls,
None => panic!("Class with name {} could not be found", stringify!($name)),
}
}};
}
/// Registers a selector with the Objective-C runtime.
///
/// Returns a [`Sel`].
///
/// [`Sel`]: crate::runtime::Sel
///
/// # Examples
///
/// ```
/// # use objc2::sel;
/// let sel = sel!(description);
/// let sel = sel!(setObject:forKey:);
/// ```
#[macro_export]
macro_rules! sel {
($name:ident) => ({
static SEL: $crate::__CachedSel = $crate::__CachedSel::new();
let name = concat!(stringify!($name), '\0');
#[allow(unused_unsafe)]
unsafe { SEL.get(name) }
});
($($name:ident :)+) => ({
static SEL: $crate::__CachedSel = $crate::__CachedSel::new();
let name = concat!($(stringify!($name), ':'),+, '\0');
#[allow(unused_unsafe)]
unsafe { SEL.get(name) }
});
}
/// Sends a message to an object or class.
///
/// The first argument can be any type that implements [`MessageReceiver`],
/// like a reference, a pointer, or an [`rc::Id`] to an object (where the
/// object implements [`Message`]).
///
/// In general this is wildly `unsafe`, even more so than sending messages in
/// Objective-C, because this macro doesn't know the expected types and
/// because Rust has more safety invariants to uphold. Make sure to review the
/// safety section below.
///
/// The syntax is similar to the message syntax in Objective-C.
///
/// Variadic arguments are not currently supported.
///
/// [`MessageReceiver`]: crate::MessageReceiver
/// [`Message`]: crate::Message
/// [`rc::Id`]: crate::rc::Id
///
/// # Panics
///
/// Panics if the `catch_all` feature is enabled and the Objective-C method
/// throws an exception. Exceptions may however still cause UB until we get
/// `extern "C-unwind"`, see [RFC-2945].
///
/// And panics if the `verify_message` feature is enabled and the Objective-C
/// method's argument's encoding does not match the encoding of the given
/// arguments. This is highly recommended to enable while testing!
///
/// # Safety
///
/// The user must ensure that the selector is a valid method and is available
/// on the given receiver.
///
/// Since this macro can't inspect header files to see the expected types, it
/// is the users responsibility that the argument types and return type are
/// what the receiver excepts for this selector. A way of doing this is by
/// defining a wrapper function:
/// ```
/// # use std::os::raw::{c_int, c_char};
/// # use objc2::msg_send;
/// # use objc2::runtime::Object;
/// unsafe fn do_something(obj: &Object, arg: c_int) -> *const c_char {
/// msg_send![obj, doSomething: arg]
/// }
/// ```
///
/// The user must also uphold any safety requirements (explicit and implicit)
/// that the method has (e.g. methods that take pointers as an argument
/// usually require that the pointer is valid and often non-null).
///
/// Additionally, the call must not violate Rust's mutability rules, e.g. if
/// passing an `&T` the Objective-C method must not mutate the variable.
///
/// If the receiver is a raw pointer the user must ensure that it is valid
/// (aligned, dereferenceable, initialized and so on). Messages to `null`
/// pointers are allowed (though discouraged), but only if the return type
/// itself is a pointer.
///
/// Finally, the method must not (yet, see [RFC-2945]) throw an exception.
///
/// # Examples
///
/// ```no_run
/// # use objc2::msg_send;
/// # use objc2::runtime::Object;
/// let obj: *mut Object;
/// # let obj: *mut Object = 0 as *mut Object;
/// let description: *const Object = unsafe { msg_send![obj, description] };
/// let _: () = unsafe { msg_send![obj, setArg1: 1 arg2: 2] };
/// // Or with an optional comma between arguments:
/// let _: () = unsafe { msg_send![obj, setArg1: 1, arg2: 2] };
/// ```
///
/// [RFC-2945]: https://rust-lang.github.io/rfcs/2945-c-unwind-abi.html
#[macro_export]
macro_rules! msg_send {
(super($obj:expr, $superclass:expr), $name:ident) => ({
let sel = $crate::sel!($name);
let result;
match $crate::MessageReceiver::send_super_message(&$obj, $superclass, sel, ()) {
Err(s) => panic!("{}", s),
Ok(r) => result = r,
}
result
});
(super($obj:expr, $superclass:expr), $($name:ident : $arg:expr $(,)?)+) => ({
let sel = $crate::sel!($($name:)+);
let result;
match $crate::MessageReceiver::send_super_message(&$obj, $superclass, sel, ($($arg,)+)) {
Err(s) => panic!("{}", s),
Ok(r) => result = r,
}
result
});
($obj:expr, $name:ident) => ({
let sel = $crate::sel!($name);
let result;
match $crate::MessageReceiver::send_message(&$obj, sel, ()) {
Err(s) => panic!("{}", s),
Ok(r) => result = r,
}
result
});
($obj:expr, $($name:ident : $arg:expr $(,)?)+) => ({
let sel = $crate::sel!($($name:)+);
let result;
match $crate::MessageReceiver::send_message(&$obj, sel, ($($arg,)+)) {
Err(s) => panic!("{}", s),
Ok(r) => result = r,
}
result
});
}