From bc7560c6dbef75c03f975409b897f90544bc6b81 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Tue, 5 Apr 2022 03:11:42 +0200 Subject: [PATCH 1/3] Test syntax of macros --- objc2/src/runtime.rs | 1 + objc2/tests/use_macros.rs | 27 ++++++++++++++- tests/ui/invalid_msg_send.rs | 17 ++++++++++ tests/ui/invalid_msg_send.stderr | 47 ++++++++++++++++++++++++++ tests/ui/invalid_msg_send_super.rs | 14 ++++++++ tests/ui/invalid_msg_send_super.stderr | 29 ++++++++++++++++ tests/ui/invalid_sel.rs | 8 +++++ tests/ui/invalid_sel.stderr | 17 ++++++++++ 8 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 tests/ui/invalid_msg_send.rs create mode 100644 tests/ui/invalid_msg_send.stderr create mode 100644 tests/ui/invalid_msg_send_super.rs create mode 100644 tests/ui/invalid_msg_send_super.stderr create mode 100644 tests/ui/invalid_sel.rs create mode 100644 tests/ui/invalid_sel.stderr diff --git a/objc2/src/runtime.rs b/objc2/src/runtime.rs index 7934fb0f1..e3fb85891 100644 --- a/objc2/src/runtime.rs +++ b/objc2/src/runtime.rs @@ -627,6 +627,7 @@ mod tests { test_sel!("abc", abc); test_sel!("abc:", abc:); test_sel!("abc:def:", abc:def:); + test_sel!("abc:def:ghi:", abc:def:ghi:); } #[test] diff --git a/objc2/tests/use_macros.rs b/objc2/tests/use_macros.rs index 10dae5ae0..28a7b6d5d 100644 --- a/objc2/tests/use_macros.rs +++ b/objc2/tests/use_macros.rs @@ -1,4 +1,4 @@ -use objc2::runtime::Object; +use objc2::runtime::{Class, Object}; use objc2::{class, msg_send, sel}; #[cfg(gnustep)] @@ -22,3 +22,28 @@ fn use_sel() { let _sel = sel!(description); let _sel = sel!(setObject:forKey:); } + +#[allow(unused)] +fn test_msg_send_comma_handling(obj: &Object, superclass: &Class) { + unsafe { + let _: () = msg_send![obj, a]; + // let _: () = msg_send![obj, a,]; + let _: () = msg_send![obj, a: 32i32]; + let _: () = msg_send![obj, a: 32i32,]; + let _: () = msg_send![obj, a: 32i32 b: 32i32]; + let _: () = msg_send![obj, a: 32i32 b: 32i32,]; + let _: () = msg_send![obj, a: 32i32, b: 32i32]; + let _: () = msg_send![obj, a: 32i32, b: 32i32,]; + } + + unsafe { + let _: () = msg_send![super(obj, superclass), a]; + // let _: () = msg_send![super(obj, superclass), a,]; + let _: () = msg_send![super(obj, superclass), a: 32i32]; + let _: () = msg_send![super(obj, superclass), a: 32i32,]; + let _: () = msg_send![super(obj, superclass), a: 32i32 b: 32i32]; + let _: () = msg_send![super(obj, superclass), a: 32i32 b: 32i32,]; + let _: () = msg_send![super(obj, superclass), a: 32i32, b: 32i32]; + let _: () = msg_send![super(obj, superclass), a: 32i32, b: 32i32,]; + } +} diff --git a/tests/ui/invalid_msg_send.rs b/tests/ui/invalid_msg_send.rs new file mode 100644 index 000000000..e84d146fd --- /dev/null +++ b/tests/ui/invalid_msg_send.rs @@ -0,0 +1,17 @@ +//! Test invalid msg_send syntax +use objc2::msg_send; +use objc2::runtime::Object; + +fn main() { + let obj: &Object; + let b = 32i32; + let d = 32i32; + let _: () = unsafe { msg_send![obj] }; + let _: () = unsafe { msg_send![obj,] }; + let _: () = unsafe { msg_send![obj, a,] }; // Could be allowed + let _: () = unsafe { msg_send![obj, a:] }; + let _: () = unsafe { msg_send![obj, a: b c] }; + let _: () = unsafe { msg_send![obj, a: b: c] }; + let _: () = unsafe { msg_send![obj, a: b, c d] }; + let _: () = unsafe { msg_send![obj, a: b: c] }; +} diff --git a/tests/ui/invalid_msg_send.stderr b/tests/ui/invalid_msg_send.stderr new file mode 100644 index 000000000..52586e4a8 --- /dev/null +++ b/tests/ui/invalid_msg_send.stderr @@ -0,0 +1,47 @@ +error: unexpected end of macro invocation + --> ui/invalid_msg_send.rs:9:39 + | +9 | let _: () = unsafe { msg_send![obj] }; + | ^ missing tokens in macro arguments + +error: unexpected end of macro invocation + --> ui/invalid_msg_send.rs:10:40 + | +10 | let _: () = unsafe { msg_send![obj,] }; + | ^ missing tokens in macro arguments + +error: no rules expected the token `,` + --> ui/invalid_msg_send.rs:11:42 + | +11 | let _: () = unsafe { msg_send![obj, a,] }; // Could be allowed + | ^ no rules expected this token in macro call + +error: unexpected end of macro invocation + --> ui/invalid_msg_send.rs:12:43 + | +12 | let _: () = unsafe { msg_send![obj, a:] }; + | ^ missing tokens in macro arguments + +error: unexpected end of macro invocation + --> ui/invalid_msg_send.rs:13:47 + | +13 | let _: () = unsafe { msg_send![obj, a: b c] }; + | ^ missing tokens in macro arguments + +error: no rules expected the token `d` + --> ui/invalid_msg_send.rs:15:49 + | +15 | let _: () = unsafe { msg_send![obj, a: b, c d] }; + | ^ no rules expected this token in macro call + +error[E0412]: cannot find type `c` in this scope + --> ui/invalid_msg_send.rs:14:47 + | +14 | let _: () = unsafe { msg_send![obj, a: b: c] }; + | ^ expecting a type here because of type ascription + +error[E0412]: cannot find type `c` in this scope + --> ui/invalid_msg_send.rs:16:47 + | +16 | let _: () = unsafe { msg_send![obj, a: b: c] }; + | ^ expecting a type here because of type ascription diff --git a/tests/ui/invalid_msg_send_super.rs b/tests/ui/invalid_msg_send_super.rs new file mode 100644 index 000000000..8d83a5b74 --- /dev/null +++ b/tests/ui/invalid_msg_send_super.rs @@ -0,0 +1,14 @@ +//! Test invalid msg_send![super(...)] syntax +use objc2::msg_send; +use objc2::runtime::{Class, Object}; + +fn main() { + let obj: &Object; + let superclass: &Class; + + let _: () = unsafe { msg_send![super, init] }; + let _: () = unsafe { msg_send![super(), init] }; + let _: () = unsafe { msg_send![super(obj), init] }; + let _: () = unsafe { msg_send![super(obj,), init] }; + let _: () = unsafe { msg_send![super(obj, superclass,), init] }; +} diff --git a/tests/ui/invalid_msg_send_super.stderr b/tests/ui/invalid_msg_send_super.stderr new file mode 100644 index 000000000..b00eb229a --- /dev/null +++ b/tests/ui/invalid_msg_send_super.stderr @@ -0,0 +1,29 @@ +error[E0433]: failed to resolve: there are too many leading `super` keywords + --> ui/invalid_msg_send_super.rs:9:36 + | +9 | let _: () = unsafe { msg_send![super, init] }; + | ^^^^^ there are too many leading `super` keywords + +error[E0433]: failed to resolve: there are too many leading `super` keywords + --> ui/invalid_msg_send_super.rs:10:36 + | +10 | let _: () = unsafe { msg_send![super(), init] }; + | ^^^^^ there are too many leading `super` keywords + +error[E0433]: failed to resolve: there are too many leading `super` keywords + --> ui/invalid_msg_send_super.rs:11:36 + | +11 | let _: () = unsafe { msg_send![super(obj), init] }; + | ^^^^^ there are too many leading `super` keywords + +error[E0433]: failed to resolve: there are too many leading `super` keywords + --> ui/invalid_msg_send_super.rs:12:36 + | +12 | let _: () = unsafe { msg_send![super(obj,), init] }; + | ^^^^^ there are too many leading `super` keywords + +error[E0433]: failed to resolve: there are too many leading `super` keywords + --> ui/invalid_msg_send_super.rs:13:36 + | +13 | let _: () = unsafe { msg_send![super(obj, superclass,), init] }; + | ^^^^^ there are too many leading `super` keywords diff --git a/tests/ui/invalid_sel.rs b/tests/ui/invalid_sel.rs new file mode 100644 index 000000000..7617215a4 --- /dev/null +++ b/tests/ui/invalid_sel.rs @@ -0,0 +1,8 @@ +//! Test invalid selector syntax +use objc2::sel; + +fn main() { + sel!(); + sel!(a: b); + sel!(a: b: c); +} diff --git a/tests/ui/invalid_sel.stderr b/tests/ui/invalid_sel.stderr new file mode 100644 index 000000000..33ed31d45 --- /dev/null +++ b/tests/ui/invalid_sel.stderr @@ -0,0 +1,17 @@ +error: unexpected end of macro invocation + --> ui/invalid_sel.rs:5:5 + | +5 | sel!(); + | ^^^^^^ missing tokens in macro arguments + +error: unexpected end of macro invocation + --> ui/invalid_sel.rs:6:14 + | +6 | sel!(a: b); + | ^ missing tokens in macro arguments + +error: unexpected end of macro invocation + --> ui/invalid_sel.rs:7:17 + | +7 | sel!(a: b: c); + | ^ missing tokens in macro arguments From cb0822f39ca4c0d8e8c2ddbb1739ef05ddccf908 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Tue, 5 Apr 2022 03:12:39 +0200 Subject: [PATCH 2/3] Clean up macro syntax --- objc2/CHANGELOG.md | 1 + objc2/src/macros.rs | 30 ++++++++++++------------------ objc2/tests/use_macros.rs | 4 ++-- tests/ui/invalid_msg_send.rs | 1 - tests/ui/invalid_msg_send.stderr | 26 ++++++++++---------------- 5 files changed, 25 insertions(+), 37 deletions(-) diff --git a/objc2/CHANGELOG.md b/objc2/CHANGELOG.md index 88b6fdcce..a19c95cee 100644 --- a/objc2/CHANGELOG.md +++ b/objc2/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * The `objc2-encode` dependency is now exposed as `objc2::encode`. * Added `Id::retain_autoreleased` to allow following Cocoas memory management rules more efficiently. +* Consistently allow trailing commas in `msg_send!`. ### Changed * **BREAKING**: Changed signature of `Id::new` and `Id::retain` from diff --git a/objc2/src/macros.rs b/objc2/src/macros.rs index f29b9af4a..a5cdd8ed3 100644 --- a/objc2/src/macros.rs +++ b/objc2/src/macros.rs @@ -44,15 +44,9 @@ macro_rules! class { /// ``` #[macro_export] macro_rules! sel { - ($name:ident) => ({ + ($first:ident $(: $($rest: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'); + let name = concat!(stringify!($first), $(':', $(stringify!($rest), ':',)*)? '\0'); #[allow(unused_unsafe)] unsafe { SEL.get(name) } }); @@ -135,8 +129,8 @@ macro_rules! sel { /// [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); + [super($obj:expr, $superclass:expr), $selector:ident $(,)?] => ({ + let sel = $crate::sel!($selector); let result; match $crate::MessageReceiver::send_super_message(&$obj, $superclass, sel, ()) { Err(s) => panic!("{}", s), @@ -144,17 +138,17 @@ macro_rules! msg_send { } result }); - (super($obj:expr, $superclass:expr), $($name:ident : $arg:expr $(,)?)+) => ({ - let sel = $crate::sel!($($name:)+); + [super($obj:expr, $superclass:expr), $($selector:ident : $argument:expr $(,)?)+] => ({ + let sel = $crate::sel!($($selector :)+); let result; - match $crate::MessageReceiver::send_super_message(&$obj, $superclass, sel, ($($arg,)+)) { + match $crate::MessageReceiver::send_super_message(&$obj, $superclass, sel, ($($argument,)+)) { Err(s) => panic!("{}", s), Ok(r) => result = r, } result }); - ($obj:expr, $name:ident) => ({ - let sel = $crate::sel!($name); + [$obj:expr, $selector:ident $(,)?] => ({ + let sel = $crate::sel!($selector); let result; match $crate::MessageReceiver::send_message(&$obj, sel, ()) { Err(s) => panic!("{}", s), @@ -162,10 +156,10 @@ macro_rules! msg_send { } result }); - ($obj:expr, $($name:ident : $arg:expr $(,)?)+) => ({ - let sel = $crate::sel!($($name:)+); + [$obj:expr, $($selector:ident : $argument:expr $(,)?)+] => ({ + let sel = $crate::sel!($($selector :)+); let result; - match $crate::MessageReceiver::send_message(&$obj, sel, ($($arg,)+)) { + match $crate::MessageReceiver::send_message(&$obj, sel, ($($argument,)+)) { Err(s) => panic!("{}", s), Ok(r) => result = r, } diff --git a/objc2/tests/use_macros.rs b/objc2/tests/use_macros.rs index 28a7b6d5d..4a36889e0 100644 --- a/objc2/tests/use_macros.rs +++ b/objc2/tests/use_macros.rs @@ -27,7 +27,7 @@ fn use_sel() { fn test_msg_send_comma_handling(obj: &Object, superclass: &Class) { unsafe { let _: () = msg_send![obj, a]; - // let _: () = msg_send![obj, a,]; + let _: () = msg_send![obj, a,]; let _: () = msg_send![obj, a: 32i32]; let _: () = msg_send![obj, a: 32i32,]; let _: () = msg_send![obj, a: 32i32 b: 32i32]; @@ -38,7 +38,7 @@ fn test_msg_send_comma_handling(obj: &Object, superclass: &Class) { unsafe { let _: () = msg_send![super(obj, superclass), a]; - // let _: () = msg_send![super(obj, superclass), a,]; + let _: () = msg_send![super(obj, superclass), a,]; let _: () = msg_send![super(obj, superclass), a: 32i32]; let _: () = msg_send![super(obj, superclass), a: 32i32,]; let _: () = msg_send![super(obj, superclass), a: 32i32 b: 32i32]; diff --git a/tests/ui/invalid_msg_send.rs b/tests/ui/invalid_msg_send.rs index e84d146fd..21e493c3c 100644 --- a/tests/ui/invalid_msg_send.rs +++ b/tests/ui/invalid_msg_send.rs @@ -8,7 +8,6 @@ fn main() { let d = 32i32; let _: () = unsafe { msg_send![obj] }; let _: () = unsafe { msg_send![obj,] }; - let _: () = unsafe { msg_send![obj, a,] }; // Could be allowed let _: () = unsafe { msg_send![obj, a:] }; let _: () = unsafe { msg_send![obj, a: b c] }; let _: () = unsafe { msg_send![obj, a: b: c] }; diff --git a/tests/ui/invalid_msg_send.stderr b/tests/ui/invalid_msg_send.stderr index 52586e4a8..58e14b638 100644 --- a/tests/ui/invalid_msg_send.stderr +++ b/tests/ui/invalid_msg_send.stderr @@ -10,38 +10,32 @@ error: unexpected end of macro invocation 10 | let _: () = unsafe { msg_send![obj,] }; | ^ missing tokens in macro arguments -error: no rules expected the token `,` - --> ui/invalid_msg_send.rs:11:42 - | -11 | let _: () = unsafe { msg_send![obj, a,] }; // Could be allowed - | ^ no rules expected this token in macro call - error: unexpected end of macro invocation - --> ui/invalid_msg_send.rs:12:43 + --> ui/invalid_msg_send.rs:11:43 | -12 | let _: () = unsafe { msg_send![obj, a:] }; +11 | let _: () = unsafe { msg_send![obj, a:] }; | ^ missing tokens in macro arguments error: unexpected end of macro invocation - --> ui/invalid_msg_send.rs:13:47 + --> ui/invalid_msg_send.rs:12:47 | -13 | let _: () = unsafe { msg_send![obj, a: b c] }; +12 | let _: () = unsafe { msg_send![obj, a: b c] }; | ^ missing tokens in macro arguments error: no rules expected the token `d` - --> ui/invalid_msg_send.rs:15:49 + --> ui/invalid_msg_send.rs:14:49 | -15 | let _: () = unsafe { msg_send![obj, a: b, c d] }; +14 | let _: () = unsafe { msg_send![obj, a: b, c d] }; | ^ no rules expected this token in macro call error[E0412]: cannot find type `c` in this scope - --> ui/invalid_msg_send.rs:14:47 + --> ui/invalid_msg_send.rs:13:47 | -14 | let _: () = unsafe { msg_send![obj, a: b: c] }; +13 | let _: () = unsafe { msg_send![obj, a: b: c] }; | ^ expecting a type here because of type ascription error[E0412]: cannot find type `c` in this scope - --> ui/invalid_msg_send.rs:16:47 + --> ui/invalid_msg_send.rs:15:47 | -16 | let _: () = unsafe { msg_send![obj, a: b: c] }; +15 | let _: () = unsafe { msg_send![obj, a: b: c] }; | ^ expecting a type here because of type ascription From 30332928ba77a2b1782c990fd28ebf2688b9c003 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sun, 3 Apr 2022 18:05:49 +0200 Subject: [PATCH 3/3] Add `msg_send_bool!` --- objc2-foundation/src/object.rs | 10 ++++------ objc2-foundation/src/string.rs | 10 ++++------ objc2-foundation/src/thread.rs | 12 ++++-------- objc2/CHANGELOG.md | 2 ++ objc2/src/bool.rs | 5 ++--- objc2/src/lib.rs | 6 +++--- objc2/src/macros.rs | 36 ++++++++++++++++++++++++++++++++++ objc2/src/runtime.rs | 3 +-- 8 files changed, 56 insertions(+), 28 deletions(-) diff --git a/objc2-foundation/src/object.rs b/objc2-foundation/src/object.rs index b844675da..ea73af139 100644 --- a/objc2-foundation/src/object.rs +++ b/objc2-foundation/src/object.rs @@ -1,6 +1,6 @@ -use objc2::msg_send; use objc2::rc::{DefaultId, Id, Owned, Shared}; -use objc2::runtime::{Bool, Class, Object}; +use objc2::runtime::{Class, Object}; +use objc2::{msg_send, msg_send_bool}; use super::NSString; @@ -17,8 +17,7 @@ impl NSObject { } pub fn is_equal(&self, other: &NSObject) -> bool { - let result: Bool = unsafe { msg_send![self, isEqual: other] }; - result.as_bool() + unsafe { msg_send_bool![self, isEqual: other] } } pub fn description(&self) -> Id { @@ -30,8 +29,7 @@ impl NSObject { } pub fn is_kind_of(&self, cls: &Class) -> bool { - let result: Bool = unsafe { msg_send![self, isKindOfClass: cls] }; - result.as_bool() + unsafe { msg_send_bool![self, isKindOfClass: cls] } } } diff --git a/objc2-foundation/src/string.rs b/objc2-foundation/src/string.rs index 49572b6ce..2e401301c 100644 --- a/objc2-foundation/src/string.rs +++ b/objc2-foundation/src/string.rs @@ -8,11 +8,11 @@ use std::os::raw::c_char; use alloc::borrow::ToOwned; use objc2::ffi; -use objc2::msg_send; use objc2::rc::DefaultId; use objc2::rc::{autoreleasepool, AutoreleasePool}; use objc2::rc::{Id, Shared}; -use objc2::runtime::{Bool, Class, Object}; +use objc2::runtime::{Class, Object}; +use objc2::{msg_send, msg_send_bool}; use crate::{NSComparisonResult, NSCopying, NSMutableCopying, NSMutableString, NSObject}; @@ -182,8 +182,7 @@ impl NSString { #[doc(alias = "hasPrefix")] #[doc(alias = "hasPrefix:")] pub fn has_prefix(&self, prefix: &NSString) -> bool { - let res: Bool = unsafe { msg_send![self, hasPrefix: prefix] }; - res.is_true() + unsafe { msg_send_bool![self, hasPrefix: prefix] } } /// Whether the given string matches the ending characters of this string. @@ -192,8 +191,7 @@ impl NSString { #[doc(alias = "hasSuffix")] #[doc(alias = "hasSuffix:")] pub fn has_suffix(&self, suffix: &NSString) -> bool { - let res: Bool = unsafe { msg_send![self, hasSuffix: suffix] }; - res.is_true() + unsafe { msg_send_bool![self, hasSuffix: suffix] } } // pub fn from_nsrange(range: NSRange) -> Id diff --git a/objc2-foundation/src/thread.rs b/objc2-foundation/src/thread.rs index 6ea3393d1..76b1470c5 100644 --- a/objc2-foundation/src/thread.rs +++ b/objc2-foundation/src/thread.rs @@ -1,6 +1,5 @@ -use objc2::msg_send; use objc2::rc::{Id, Shared}; -use objc2::runtime::Bool; +use objc2::{msg_send, msg_send_bool}; use crate::{NSObject, NSString}; @@ -34,8 +33,7 @@ impl NSThread { /// Returns `true` if the thread is the main thread. pub fn is_main(&self) -> bool { - let res: Bool = unsafe { msg_send![self, isMainThread] }; - res.is_true() + unsafe { msg_send_bool![self, isMainThread] } } /// The name of the thread. @@ -47,14 +45,12 @@ impl NSThread { /// Whether the application is multithreaded according to Cocoa. pub fn is_multi_threaded() -> bool { - let res: Bool = unsafe { msg_send![NSThread::class(), isMultiThreaded] }; - res.is_true() + unsafe { msg_send_bool![NSThread::class(), isMultiThreaded] } } /// Whether the current thread is the main thread. pub fn is_main_thread() -> bool { - let res: Bool = unsafe { msg_send![NSThread::class(), isMainThread] }; - res.is_true() + unsafe { msg_send_bool![NSThread::class(), isMainThread] } } #[cfg(test)] diff --git a/objc2/CHANGELOG.md b/objc2/CHANGELOG.md index a19c95cee..7155d1ada 100644 --- a/objc2/CHANGELOG.md +++ b/objc2/CHANGELOG.md @@ -16,6 +16,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Added `Id::retain_autoreleased` to allow following Cocoas memory management rules more efficiently. * Consistently allow trailing commas in `msg_send!`. +* Added `msg_send_bool!`, a less error-prone version of `msg_send!` for + Objective-C methods that return `BOOL`. ### Changed * **BREAKING**: Changed signature of `Id::new` and `Id::retain` from diff --git a/objc2/src/bool.rs b/objc2/src/bool.rs index e6b94a740..d8e69dd9e 100644 --- a/objc2/src/bool.rs +++ b/objc2/src/bool.rs @@ -16,11 +16,10 @@ use core::fmt; /// # Example /// /// ```no_run -/// use objc2::{class, msg_send}; +/// use objc2::{class, msg_send, msg_send_bool}; /// use objc2::runtime::{Object, Bool}; /// let ns_value: *mut Object = unsafe { msg_send![class!(NSValue), initWithBool: Bool::YES] }; -/// let rtn: Bool = unsafe { msg_send![ns_value, boolValue] }; -/// assert!(rtn.as_bool()); +/// assert!(unsafe { msg_send_bool![ns_value, boolValue] }); /// ``` #[repr(transparent)] // We don't implement comparison traits because they could be implemented with diff --git a/objc2/src/lib.rs b/objc2/src/lib.rs index e9c13a896..94879faa6 100644 --- a/objc2/src/lib.rs +++ b/objc2/src/lib.rs @@ -29,7 +29,7 @@ //! #![cfg_attr(apple, doc = "```")] #![cfg_attr(not(apple), doc = "```no_run")] -//! use objc2::{class, msg_send}; +//! use objc2::{class, msg_send, msg_send_bool}; //! use objc2::ffi::NSUInteger; //! use objc2::rc::{Id, Owned}; //! use objc2::runtime::{Bool, Object}; @@ -43,8 +43,8 @@ //! //! // Usage //! let hash: NSUInteger = unsafe { msg_send![obj, hash] }; -//! let is_kind: Bool = unsafe { msg_send![obj, isKindOfClass: cls] }; -//! assert!(is_kind.as_bool()); +//! let is_kind = unsafe { msg_send_bool![obj, isKindOfClass: cls] }; +//! assert!(is_kind); //! ``` //! //! Note that this very simple example contains **a lot** of `unsafe` (which diff --git a/objc2/src/macros.rs b/objc2/src/macros.rs index a5cdd8ed3..6d9ea7356 100644 --- a/objc2/src/macros.rs +++ b/objc2/src/macros.rs @@ -166,3 +166,39 @@ macro_rules! msg_send { result }); } + +/// A less error-prone version of [`msg_send!`] for methods returning `BOOL`. +/// +/// Objective-C's `BOOL` is different from Rust's [`bool`] (see [`Bool`]), so +/// a conversion step must be performed before using it - this macro does that +/// for you! +/// +/// [`Bool`]: crate::runtime::Bool +/// +/// Equivalent to the following: +/// +/// ```ignore +/// # use objc2::msg_send; +/// # use objc2::runtime::Bool; +/// # let obj: *mut Object = 0 as *mut Object; +/// { +/// let result: Bool = msg_send![obj, selector]; +/// result.as_bool() +/// }; +/// ``` +/// +/// # Examples +/// +/// ```no_run +/// # use objc2::msg_send_bool; +/// # use objc2::runtime::Object; +/// # let obj: *mut Object = 0 as *mut Object; +/// assert!(unsafe { msg_send_bool![obj, isEqual: obj] }); +/// ``` +#[macro_export] +macro_rules! msg_send_bool { + [$($msg_send_args:tt)+] => ({ + let result: $crate::runtime::Bool = $crate::msg_send![$($msg_send_args)+]; + result.as_bool() + }); +} diff --git a/objc2/src/runtime.rs b/objc2/src/runtime.rs index e3fb85891..7bf2d5ade 100644 --- a/objc2/src/runtime.rs +++ b/objc2/src/runtime.rs @@ -170,8 +170,7 @@ impl Ivar { /// Returns the offset of self. pub fn offset(&self) -> isize { - let offset = unsafe { ffi::ivar_getOffset(self.as_ptr()) }; - offset as isize + unsafe { ffi::ivar_getOffset(self.as_ptr()) } } /// Returns the `Encoding` of self.