Skip to content

Commit c6e1ecb

Browse files
committed
Support msg_send_id![super, ...] for all non-ARC selectors
1 parent aed5cdd commit c6e1ecb

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

objc2/src/__macro_helpers.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ pub trait MsgSendId<T, U> {
2323
) -> Result<Option<U>, MessageError>;
2424
}
2525

26+
#[doc(hidden)]
27+
pub trait MsgSendSuperId<T, U> {
28+
unsafe fn send_super_message_id<A: MessageArguments>(
29+
obj: T,
30+
superclass: &Class,
31+
sel: Sel,
32+
args: A,
33+
) -> Result<Option<U>, MessageError>;
34+
}
35+
2636
// `new`
2737
impl<T: ?Sized + Message, O: Ownership> MsgSendId<&'_ Class, Id<T, O>>
2838
for Assert<true, false, false, false>
@@ -104,6 +114,26 @@ impl<T: MessageReceiver, U: Message, O: Ownership> MsgSendId<T, Id<U, O>>
104114
}
105115
}
106116

117+
// Super: All other selectors
118+
impl<T: MessageReceiver, U: Message, O: Ownership> MsgSendSuperId<T, Id<U, O>>
119+
for Assert<false, false, false, false>
120+
{
121+
#[inline(always)]
122+
unsafe fn send_super_message_id<A: MessageArguments>(
123+
obj: T,
124+
superclass: &Class,
125+
sel: Sel,
126+
args: A,
127+
) -> Result<Option<Id<U, O>>, MessageError> {
128+
// All code between the message send and the `retain_autoreleased`
129+
// must be able to be optimized away for this to work.
130+
unsafe {
131+
MessageReceiver::send_super_message(obj, superclass, sel, args)
132+
.map(|r| Id::retain_autoreleased(r))
133+
}
134+
}
135+
}
136+
107137
// https://clang.llvm.org/docs/AutomaticReferenceCounting.html#arc-method-families
108138
#[doc(hidden)]
109139
pub const fn in_method_family(mut selector: &[u8], mut family: &[u8]) -> bool {
@@ -206,6 +236,18 @@ mod tests {
206236
let _desc: Option<Id<Object, Shared>> = unsafe { msg_send_id![&obj, description] };
207237
}
208238

239+
#[test]
240+
fn test_msg_send_super_id() {
241+
// We send the messages to the class itself instead of it's actual
242+
// superclass, just to verify that the macro works.
243+
// TODO: Better solution!
244+
let cls = class!(NSObject);
245+
let obj: Id<Object, Owned> = unsafe { msg_send_id![cls, new].unwrap() };
246+
247+
let _desc: Option<Id<Object, Shared>> =
248+
unsafe { msg_send_id![super(&obj, cls), description] };
249+
}
250+
209251
#[test]
210252
fn test_in_method_family() {
211253
// Common cases

objc2/src/macros.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,28 @@ macro_rules! msg_send_bool {
239239
/// [`Id::autorelease`]: crate::rc::Id::autorelease
240240
#[macro_export]
241241
macro_rules! msg_send_id {
242+
[super($obj:expr, $superclass:expr), $selector:ident $(,)?] => ({
243+
let sel = $crate::sel!($selector);
244+
const NAME: &[u8] = stringify!($selector).as_bytes();
245+
$crate::msg_send_id!(@__get_assert_consts NAME);
246+
let result: Option<$crate::rc::Id<_, _>>;
247+
match <X as $crate::__macro_helpers::MsgSendSuperId<_, _>>::send_super_message_id($obj, $superclass, sel, ()) {
248+
Err(s) => panic!("{}", s),
249+
Ok(r) => result = r,
250+
}
251+
result
252+
});
253+
[super($obj:expr, $superclass:expr), $($selector:ident : $argument:expr),+ $(,)?] => ({
254+
let sel = $crate::sel!($($selector:)+);
255+
const NAME: &[u8] = concat!($(stringify!($selector), ':'),+).as_bytes();
256+
$crate::msg_send_id!(@__get_assert_consts NAME);
257+
let result: Option<$crate::rc::Id<_, _>>;
258+
match <X as $crate::__macro_helpers::MsgSendSuperId<_, _>>::send_super_message_id($obj, $superclass, sel, ($($argument,)+)) {
259+
Err(s) => panic!("{}", s),
260+
Ok(r) => result = r,
261+
}
262+
result
263+
});
242264
[$obj:expr, retain $(,)?] => ({
243265
$crate::__macro_helpers::compile_error!(
244266
"msg_send_id![obj, retain] is not supported. Use `Id::retain` instead"

0 commit comments

Comments
 (0)