From a792820a707c457a4da6ae4db8ad36cfc019a839 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 15 Jun 2022 22:32:22 +0200 Subject: [PATCH 1/3] Support msg_send_id![super, ...] for all non-ARC selectors --- objc2/src/__macro_helpers.rs | 42 ++++++++++++++++++++++++++++++++++++ objc2/src/macros.rs | 23 ++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/objc2/src/__macro_helpers.rs b/objc2/src/__macro_helpers.rs index e8a25c457..99eeee0d8 100644 --- a/objc2/src/__macro_helpers.rs +++ b/objc2/src/__macro_helpers.rs @@ -49,6 +49,16 @@ pub trait MsgSendId { ) -> Result, MessageError>; } +#[doc(hidden)] +pub trait MsgSendSuperId { + unsafe fn send_super_message_id( + obj: T, + superclass: &Class, + sel: Sel, + args: A, + ) -> Result, MessageError>; +} + // `new` impl MsgSendId<&'_ Class, Id> for RetainSemantics @@ -128,6 +138,26 @@ impl MsgSendId> } } +// Super: All other selectors +impl MsgSendSuperId> + for RetainSemantics +{ + #[inline(always)] + unsafe fn send_super_message_id( + obj: T, + superclass: &Class, + sel: Sel, + args: A, + ) -> Result>, MessageError> { + // All code between the message send and the `retain_autoreleased` + // must be able to be optimized away for this to work. + unsafe { + MessageReceiver::send_super_message(obj, superclass, sel, args) + .map(|r| Id::retain_autoreleased(r)) + } + } +} + /// Checks whether a given selector is said to be in a given selector family. /// /// @@ -280,6 +310,18 @@ mod tests { expected.assert_current(); } + #[test] + fn test_msg_send_super_id() { + // We send the messages to the class itself instead of it's actual + // superclass, just to verify that the macro works. + // TODO: Better solution! + let cls = class!(NSObject); + let obj: Id = unsafe { msg_send_id![cls, new].unwrap() }; + + let _desc: Option> = + unsafe { msg_send_id![super(&obj, cls), description] }; + } + #[test] fn test_in_selector_family() { // Common cases diff --git a/objc2/src/macros.rs b/objc2/src/macros.rs index 86509da17..43cc2ae96 100644 --- a/objc2/src/macros.rs +++ b/objc2/src/macros.rs @@ -384,6 +384,29 @@ macro_rules! msg_send_bool { /// ``` #[macro_export] macro_rules! msg_send_id { + [super($obj:expr, $superclass:expr), $selector:ident $(,)?] => ({ + $crate::__msg_send_id_helper!(@verify $selector); + let sel = $crate::sel!($selector); + const NAME: &[u8] = stringify!($selector).as_bytes(); + $crate::__msg_send_id_helper!(@get_assert_consts NAME); + let result: Option<$crate::rc::Id<_, _>>; + match >::send_super_message_id($obj, $superclass, sel, ()) { + Err(s) => panic!("{}", s), + Ok(r) => result = r, + } + result + }); + [super($obj:expr, $superclass:expr), $($selector:ident : $argument:expr),+ $(,)?] => ({ + let sel = $crate::sel!($($selector:)+); + const NAME: &[u8] = concat!($(stringify!($selector), ':'),+).as_bytes(); + $crate::__msg_send_id_helper!(@get_assert_consts NAME); + let result: Option<$crate::rc::Id<_, _>>; + match >::send_super_message_id($obj, $superclass, sel, ($($argument,)+)) { + Err(s) => panic!("{}", s), + Ok(r) => result = r, + } + result + }); [$obj:expr, $selector:ident $(,)?] => ({ $crate::__msg_send_id_helper!(@verify $selector); let sel = $crate::sel!($selector); From 8106a8d1d0df18eb96dbac627bfae55e683472bc Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 15 Jun 2022 22:32:36 +0200 Subject: [PATCH 2/3] Support msg_send_id![super, init] --- objc2/src/__macro_helpers.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/objc2/src/__macro_helpers.rs b/objc2/src/__macro_helpers.rs index 99eeee0d8..beb1c2037 100644 --- a/objc2/src/__macro_helpers.rs +++ b/objc2/src/__macro_helpers.rs @@ -1,3 +1,5 @@ +use core::mem::ManuallyDrop; + use crate::rc::{Id, Ownership}; use crate::runtime::{Class, Sel}; use crate::{Message, MessageArguments, MessageError, MessageReceiver}; @@ -108,6 +110,27 @@ impl MsgSendId>, Id> } } +// Super: `init`. Takes a non-null object and returns a non-initialized object +// +// Should theoretically make it easy to use in declared `init` methods, once +// they've received an ergonomics overhaul +impl MsgSendSuperId, Id> + for RetainSemantics +{ + #[inline(always)] + unsafe fn send_super_message_id( + obj: Id, + superclass: &Class, + sel: Sel, + args: A, + ) -> Result>, MessageError> { + let ptr = Id::consume_as_ptr(ManuallyDrop::new(obj)); + unsafe { + MessageReceiver::send_super_message(ptr, superclass, sel, args).map(|r| Id::new(r)) + } + } +} + // `copy` and `mutableCopy` impl MsgSendId> for RetainSemantics @@ -316,7 +339,11 @@ mod tests { // superclass, just to verify that the macro works. // TODO: Better solution! let cls = class!(NSObject); - let obj: Id = unsafe { msg_send_id![cls, new].unwrap() }; + + let obj = unsafe { msg_send_id![cls, alloc] }; + + let obj = obj.unwrap(); // Required on super + let obj: Id = unsafe { msg_send_id![super(obj, cls), init].unwrap() }; let _desc: Option> = unsafe { msg_send_id![super(&obj, cls), description] }; From 3ceff5ad7fbdbd14405f6121fa08817410e8b34a Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Wed, 15 Jun 2022 05:35:51 +0200 Subject: [PATCH 3/3] Support the rest of the super selectors [WIP] --- objc2/src/__macro_helpers.rs | 61 +++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/objc2/src/__macro_helpers.rs b/objc2/src/__macro_helpers.rs index beb1c2037..19929beae 100644 --- a/objc2/src/__macro_helpers.rs +++ b/objc2/src/__macro_helpers.rs @@ -75,6 +75,23 @@ impl MsgSendId<&'_ Class, Id> } } +// Super: `new`, TODO: Can this ever happen? +impl MsgSendSuperId<&'_ Class, Id> + for RetainSemantics +{ + #[inline(always)] + unsafe fn send_super_message_id( + obj: &Class, + superclass: &Class, + sel: Sel, + args: A, + ) -> Result>, MessageError> { + unsafe { + MessageReceiver::send_super_message(obj, superclass, sel, args).map(|r| Id::new(r)) + } + } +} + // `alloc`, should mark the return value as "allocated, not initialized" somehow impl MsgSendId<&'_ Class, Id> for RetainSemantics @@ -89,6 +106,23 @@ impl MsgSendId<&'_ Class, Id> } } +// Super: `alloc`, TODO: Can this ever happen? +impl MsgSendSuperId<&'_ Class, Id> + for RetainSemantics +{ + #[inline(always)] + unsafe fn send_super_message_id( + cls: &Class, + superclass: &Class, + sel: Sel, + args: A, + ) -> Result>, MessageError> { + unsafe { + MessageReceiver::send_super_message(cls, superclass, sel, args).map(|r| Id::new(r)) + } + } +} + // `init`, should mark the input value as "allocated, not initialized" somehow impl MsgSendId>, Id> for RetainSemantics @@ -145,6 +179,23 @@ impl MsgSendId MsgSendSuperId> + for RetainSemantics +{ + #[inline(always)] + unsafe fn send_super_message_id( + obj: T, + superclass: &Class, + sel: Sel, + args: A, + ) -> Result>, MessageError> { + unsafe { + MessageReceiver::send_super_message(obj, superclass, sel, args).map(|r| Id::new(r)) + } + } +} + // All other selectors impl MsgSendId> for RetainSemantics @@ -334,17 +385,25 @@ mod tests { } #[test] + #[ignore = "TMP"] fn test_msg_send_super_id() { // We send the messages to the class itself instead of it's actual // superclass, just to verify that the macro works. // TODO: Better solution! let cls = class!(NSObject); - let obj = unsafe { msg_send_id![cls, alloc] }; + let _obj: Id = unsafe { msg_send_id![super(cls, cls), new].unwrap() }; + + let obj = unsafe { msg_send_id![super(cls, cls), alloc] }; let obj = obj.unwrap(); // Required on super let obj: Id = unsafe { msg_send_id![super(obj, cls), init].unwrap() }; + let _copy: Id = unsafe { msg_send_id![super(&obj, cls), copy].unwrap() }; + + let _mutable_copy: Id = + unsafe { msg_send_id![super(&obj, cls), mutableCopy].unwrap() }; + let _desc: Option> = unsafe { msg_send_id![super(&obj, cls), description] }; }