Skip to content

Commit 7c8cfcc

Browse files
committed
Allow omitting the superclass in msg_send![super(...), ...]
Uses ClassType to get the superclass instead.
1 parent ace0604 commit 7c8cfcc

13 files changed

+184
-25
lines changed

objc2/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
2121
`NSData::class()`.
2222
* Added `Id::into_super`.
2323
* Added `extern_methods!` macro.
24+
* Added ability to call `msg_send![super(obj), ...]` without explicitly
25+
specifying the superclass.
2426

2527
### Changed
2628
* **BREAKING**: Change syntax in `extern_class!` macro to be more Rust-like.

objc2/examples/delegate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ declare_class!(
3232
unsafe impl CustomAppDelegate {
3333
#[sel(initWith:another:)]
3434
fn init_with(self: &mut Self, ivar: u8, another_ivar: Bool) -> *mut Self {
35-
let this: *mut Self = unsafe { msg_send![super(self, NSResponder::class()), init] };
35+
let this: *mut Self = unsafe { msg_send![super(self), init] };
3636
if let Some(this) = unsafe { this.as_mut() } {
3737
// TODO: Allow initialization through MaybeUninit
3838
*this.ivar = ivar;

objc2/src/macros.rs

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,10 @@ macro_rules! __class_inner {
620620
/// implements [`MessageReceiver`], like a reference or a pointer to an
621621
/// object, or even a reference to an [`rc::Id`] containing an object.
622622
///
623+
/// The expression can be wrapped in `super`, with an optional superclass
624+
/// as the second argument. If no specific superclass is specified, the
625+
/// direct superclass is retrieved from [`ClassType`].
626+
///
623627
/// All arguments, and the return type, must implement [`Encode`].
624628
///
625629
/// This macro translates into a call to [`sel!`], and afterwards a fully
@@ -633,6 +637,7 @@ macro_rules! __class_inner {
633637
///
634638
/// [`MessageReceiver`]: crate::MessageReceiver
635639
/// [`rc::Id`]: crate::rc::Id
640+
/// [`ClassType`]: crate::ClassType
636641
/// [`Encode`]: crate::Encode
637642
/// [`sel!`]: crate::sel
638643
/// [`MessageReceiver::send_message`]: crate::MessageReceiver::send_message
@@ -691,25 +696,68 @@ macro_rules! __class_inner {
691696
///
692697
/// # Examples
693698
///
699+
/// Sending messages to an object.
700+
///
694701
/// ```no_run
695-
/// # use objc2::msg_send;
696-
/// # use objc2::runtime::Object;
702+
/// use objc2::msg_send;
703+
/// use objc2::runtime::Object;
704+
///
697705
/// let obj: *mut Object;
698-
/// # let obj: *mut Object = 0 as *mut Object;
706+
/// # obj = 0 as *mut Object;
699707
/// let description: *const Object = unsafe { msg_send![obj, description] };
700708
/// // Usually you'd use msg_send_id here ^
701-
/// let _: () = unsafe { msg_send![obj, setArg1: 1u32, arg2: 2i32] };
709+
/// let _: () = unsafe { msg_send![obj, setArg1: 1u32, arg2: 2u8] };
702710
/// let arg1: i32 = unsafe { msg_send![obj, getArg1] };
703-
/// let arg2: i32 = unsafe { msg_send![obj, getArg2] };
711+
/// let arg2: u8 = unsafe { msg_send![obj, getArg2] };
712+
/// ```
713+
///
714+
/// Sending messages to the direct superclass of an object.
715+
///
716+
/// ```no_run
717+
/// use objc2::msg_send;
718+
/// # use objc2::ns_string;
719+
/// # use objc2::foundation::{NSString as MyObject};
720+
///
721+
/// let obj: &MyObject; // Some object that implements ClassType
722+
/// # obj = ns_string!("");
723+
/// let _: () = unsafe { msg_send![super(obj), someMethod] };
724+
/// ```
725+
///
726+
/// Sending messages to a specific superclass of an object.
727+
///
728+
/// ```no_run
729+
/// # use objc2::class;
730+
/// use objc2::msg_send;
731+
/// use objc2::runtime::{Class, Object};
732+
///
733+
/// // Since we specify the superclass ourselves, this doesn't need to
734+
/// // implement ClassType
735+
/// let obj: *mut Object;
736+
/// # obj = 0 as *mut Object;
737+
/// let superclass: &Class;
738+
/// # superclass = class!(NSObject);
739+
/// let arg3: u32 = unsafe { msg_send![super(obj, superclass), getArg3] };
704740
/// ```
705741
#[macro_export]
706742
macro_rules! msg_send {
707-
[super($obj:expr, $superclass:expr), $selector:ident $(,)?] => ({
743+
[super($obj:expr), $selector:ident $(,)?] => ({
708744
let sel = $crate::sel!($selector);
709745
let result;
710746
// Note: `sel` and `result` can be accessed from the `obj` and
711747
// `superclass` expressions - we won't (yet) bother with preventing
712748
// that though.
749+
result = $crate::MessageReceiver::__send_super_message_static($obj, sel, ());
750+
result
751+
});
752+
[super($obj:expr), $($selector:ident : $argument:expr),+ $(,)?] => ({
753+
let sel = $crate::sel!($($selector :)+);
754+
let result;
755+
result = $crate::MessageReceiver::__send_super_message_static($obj, sel, ($($argument,)+));
756+
result
757+
});
758+
[super($obj:expr, $superclass:expr), $selector:ident $(,)?] => ({
759+
let sel = $crate::sel!($selector);
760+
let result;
713761
result = $crate::MessageReceiver::send_super_message($obj, $superclass, sel, ());
714762
result
715763
});

objc2/src/macros/declare_class.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ macro_rules! __inner_declare_class {
253253
/// #[sel(initWithFoo:)]
254254
/// fn init_with(&mut self, foo: u8) -> Option<&mut Self> {
255255
/// let this: Option<&mut Self> = unsafe {
256-
/// msg_send![super(self, NSObject::class()), init]
256+
/// msg_send![super(self), init]
257257
/// };
258258
/// this.map(|this| {
259259
/// // TODO: Initialization through MaybeUninit

objc2/src/message/mod.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use core::ptr::NonNull;
44

55
use crate::rc::{Id, Owned, Ownership};
66
use crate::runtime::{Class, Imp, Object, Sel};
7-
use crate::{Encode, EncodeArguments, RefEncode};
7+
use crate::{ClassType, Encode, EncodeArguments, RefEncode};
88

99
#[cfg(feature = "catch-all")]
1010
#[track_caller]
@@ -136,11 +136,15 @@ pub(crate) mod private {
136136
/// This is mostly an implementation detail; you'll want to implement
137137
/// [`Message`] for your type instead.
138138
///
139+
///
139140
/// # Safety
140141
///
141142
/// This is a sealed trait, and should not need to be implemented. Open an
142143
/// issue if you know a use-case where this restrition should be lifted!
143144
pub unsafe trait MessageReceiver: private::Sealed + Sized {
145+
#[doc(hidden)]
146+
type __Inner: ?Sized;
147+
144148
#[doc(hidden)]
145149
fn __as_raw_receiver(self) -> *mut Object;
146150

@@ -155,6 +159,7 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized {
155159
///
156160
/// [runtime]: https://developer.apple.com/documentation/objectivec/objective-c_runtime?language=objc
157161
///
162+
///
158163
/// # Safety
159164
///
160165
/// This shares the same safety requirements as [`msg_send!`].
@@ -189,7 +194,7 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized {
189194
unsafe { send_unverified(this, sel, args) }
190195
}
191196

192-
/// Sends a message to self's superclass with the given selector and
197+
/// Sends a message to a specific superclass with the given selector and
193198
/// arguments.
194199
///
195200
/// The correct version of `objc_msgSend_super` will be chosen based on the
@@ -201,6 +206,7 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized {
201206
///
202207
/// [runtime]: https://developer.apple.com/documentation/objectivec/objective-c_runtime?language=objc
203208
///
209+
///
204210
/// # Safety
205211
///
206212
/// This shares the same safety requirements as
@@ -229,33 +235,54 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized {
229235
}
230236
unsafe { send_super_unverified(this, superclass, sel, args) }
231237
}
238+
239+
#[inline]
240+
#[track_caller]
241+
#[doc(hidden)]
242+
unsafe fn __send_super_message_static<A, R>(self, sel: Sel, args: A) -> R
243+
where
244+
Self::__Inner: ClassType,
245+
<Self::__Inner as ClassType>::Super: ClassType,
246+
A: MessageArguments,
247+
R: Encode,
248+
{
249+
unsafe { self.send_super_message(<Self::__Inner as ClassType>::Super::class(), sel, args) }
250+
}
232251
}
233252

234253
// Note that we implement MessageReceiver for unsized types as well, this is
235254
// to support `extern type`s in the future, not because we want to allow DSTs.
236255

237256
unsafe impl<T: Message + ?Sized> MessageReceiver for *const T {
257+
type __Inner = T;
258+
238259
#[inline]
239260
fn __as_raw_receiver(self) -> *mut Object {
240261
(self as *mut T).cast()
241262
}
242263
}
243264

244265
unsafe impl<T: Message + ?Sized> MessageReceiver for *mut T {
266+
type __Inner = T;
267+
245268
#[inline]
246269
fn __as_raw_receiver(self) -> *mut Object {
247270
self.cast()
248271
}
249272
}
250273

251274
unsafe impl<T: Message + ?Sized> MessageReceiver for NonNull<T> {
275+
type __Inner = T;
276+
252277
#[inline]
253278
fn __as_raw_receiver(self) -> *mut Object {
254279
self.as_ptr().cast()
255280
}
256281
}
257282

258283
unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a T {
284+
type __Inner = T;
285+
259286
#[inline]
260287
fn __as_raw_receiver(self) -> *mut Object {
261288
let ptr: *const T = self;
@@ -264,6 +291,8 @@ unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a T {
264291
}
265292

266293
unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a mut T {
294+
type __Inner = T;
295+
267296
#[inline]
268297
fn __as_raw_receiver(self) -> *mut Object {
269298
let ptr: *mut T = self;
@@ -272,34 +301,44 @@ unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a mut T {
272301
}
273302

274303
unsafe impl<'a, T: Message + ?Sized, O: Ownership> MessageReceiver for &'a Id<T, O> {
304+
type __Inner = T;
305+
275306
#[inline]
276307
fn __as_raw_receiver(self) -> *mut Object {
277308
(Id::as_ptr(self) as *mut T).cast()
278309
}
279310
}
280311

281312
unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a mut Id<T, Owned> {
313+
type __Inner = T;
314+
282315
#[inline]
283316
fn __as_raw_receiver(self) -> *mut Object {
284317
Id::as_mut_ptr(self).cast()
285318
}
286319
}
287320

288321
unsafe impl<T: Message + ?Sized, O: Ownership> MessageReceiver for ManuallyDrop<Id<T, O>> {
322+
type __Inner = T;
323+
289324
#[inline]
290325
fn __as_raw_receiver(self) -> *mut Object {
291326
Id::consume_as_ptr(self).cast()
292327
}
293328
}
294329

295330
unsafe impl MessageReceiver for *const Class {
331+
type __Inner = Class;
332+
296333
#[inline]
297334
fn __as_raw_receiver(self) -> *mut Object {
298335
(self as *mut Class).cast()
299336
}
300337
}
301338

302339
unsafe impl<'a> MessageReceiver for &'a Class {
340+
type __Inner = Class;
341+
303342
#[inline]
304343
fn __as_raw_receiver(self) -> *mut Object {
305344
let ptr: *const Class = self;

objc2/src/rc/test_object.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,25 +77,25 @@ declare_class!(
7777
#[sel(init)]
7878
fn init(&mut self) -> *mut Self {
7979
TEST_DATA.with(|data| data.borrow_mut().init += 1);
80-
unsafe { msg_send![super(self, NSObject::class()), init] }
80+
unsafe { msg_send![super(self), init] }
8181
}
8282

8383
#[sel(retain)]
8484
fn retain(&self) -> *mut Self {
8585
TEST_DATA.with(|data| data.borrow_mut().retain += 1);
86-
unsafe { msg_send![super(self, NSObject::class()), retain] }
86+
unsafe { msg_send![super(self), retain] }
8787
}
8888

8989
#[sel(release)]
9090
fn release(&self) {
9191
TEST_DATA.with(|data| data.borrow_mut().release += 1);
92-
unsafe { msg_send![super(self, NSObject::class()), release] }
92+
unsafe { msg_send![super(self), release] }
9393
}
9494

9595
#[sel(autorelease)]
9696
fn autorelease(&self) -> *mut Self {
9797
TEST_DATA.with(|data| data.borrow_mut().autorelease += 1);
98-
unsafe { msg_send![super(self, NSObject::class()), autorelease] }
98+
unsafe { msg_send![super(self), autorelease] }
9999
}
100100

101101
#[sel(dealloc)]
@@ -107,7 +107,7 @@ declare_class!(
107107
#[sel(_tryRetain)]
108108
unsafe fn try_retain(&self) -> Bool {
109109
TEST_DATA.with(|data| data.borrow_mut().try_retain += 1);
110-
let res = unsafe { msg_send_bool![super(self, NSObject::class()), _tryRetain] };
110+
let res = unsafe { msg_send_bool![super(self), _tryRetain] };
111111
if !res {
112112
TEST_DATA.with(|data| data.borrow_mut().try_retain -= 1);
113113
TEST_DATA.with(|data| data.borrow_mut().try_retain_fail += 1);

objc2/src/test_utils.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,26 @@ impl crate::message::private::Sealed for &mut CustomObject {}
2727
impl crate::message::private::Sealed for ManuallyDrop<CustomObject> {}
2828

2929
unsafe impl MessageReceiver for &CustomObject {
30+
type __Inner = Object;
31+
3032
#[inline]
3133
fn __as_raw_receiver(self) -> *mut Object {
3234
self.obj
3335
}
3436
}
3537

3638
unsafe impl MessageReceiver for &mut CustomObject {
39+
type __Inner = Object;
40+
3741
#[inline]
3842
fn __as_raw_receiver(self) -> *mut Object {
3943
self.obj
4044
}
4145
}
4246

4347
unsafe impl MessageReceiver for ManuallyDrop<CustomObject> {
48+
type __Inner = Object;
49+
4450
#[inline]
4551
fn __as_raw_receiver(self) -> *mut Object {
4652
self.obj

objc2/tests/no_prelude.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,22 @@ pub fn test_class() {
9595
let _class = new_objc2::class!(NSObject);
9696
}
9797

98-
pub fn test_msg_send(obj: &new_objc2::runtime::Object) {
98+
pub fn test_msg_send(obj: &new_objc2::foundation::NSString) {
9999
let superclass = obj.class().superclass().unwrap();
100100
let _: () = unsafe { new_objc2::msg_send![obj, a] };
101101
let _: () = unsafe { new_objc2::msg_send![obj, a: obj, b: obj] };
102+
let _: () = unsafe { new_objc2::msg_send![super(obj), a] };
103+
let _: () = unsafe { new_objc2::msg_send![super(obj), a: obj, b: obj] };
102104
let _: () = unsafe { new_objc2::msg_send![super(obj, superclass), a] };
103105
let _: () = unsafe { new_objc2::msg_send![super(obj, superclass), a: obj, b: obj] };
104106
}
105107

106-
pub fn test_msg_send_bool(obj: &new_objc2::runtime::Object) {
108+
pub fn test_msg_send_bool(obj: &new_objc2::foundation::NSString) {
107109
let superclass = obj.class().superclass().unwrap();
108110
unsafe { new_objc2::msg_send_bool![obj, a] };
109111
unsafe { new_objc2::msg_send_bool![obj, a: obj, b: obj] };
112+
unsafe { new_objc2::msg_send_bool![super(obj), a] };
113+
unsafe { new_objc2::msg_send_bool![super(obj), a: obj, b: obj] };
110114
unsafe { new_objc2::msg_send_bool![super(obj, superclass), a] };
111115
unsafe { new_objc2::msg_send_bool![super(obj, superclass), a: obj, b: obj] };
112116
}

objc2/tests/use_macros.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use objc2::foundation::NSString;
12
use objc2::runtime::{Class, Object};
23
use objc2::{class, msg_send, sel};
34

@@ -24,7 +25,7 @@ fn use_sel() {
2425
}
2526

2627
#[allow(unused)]
27-
fn test_msg_send_comma_handling(obj: &Object, superclass: &Class) {
28+
fn test_msg_send_comma_handling(obj: &NSString, superclass: &Class) {
2829
unsafe {
2930
let _: () = msg_send![obj, a];
3031
let _: () = msg_send![obj, a,];
@@ -46,4 +47,13 @@ fn test_msg_send_comma_handling(obj: &Object, superclass: &Class) {
4647
let _: () = msg_send![super(obj, superclass), a: 32i32, b: 32i32];
4748
let _: () = msg_send![super(obj, superclass), a: 32i32, b: 32i32,];
4849
}
50+
51+
unsafe {
52+
let _: () = msg_send![super(obj), a];
53+
let _: () = msg_send![super(obj), a,];
54+
let _: () = msg_send![super(obj), a: 32i32];
55+
let _: () = msg_send![super(obj), a: 32i32,];
56+
let _: () = msg_send![super(obj), a: 32i32, b: 32i32];
57+
let _: () = msg_send![super(obj), a: 32i32, b: 32i32,];
58+
}
4959
}

0 commit comments

Comments
 (0)