Skip to content

Commit 2b1eefb

Browse files
authored
Merge pull request #147 from madsmtm/msg_send_bool
Add `msg_send_bool!`
2 parents ef9d853 + 3033292 commit 2b1eefb

File tree

15 files changed

+221
-47
lines changed

15 files changed

+221
-47
lines changed

objc2-foundation/src/object.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use objc2::msg_send;
21
use objc2::rc::{DefaultId, Id, Owned, Shared};
3-
use objc2::runtime::{Bool, Class, Object};
2+
use objc2::runtime::{Class, Object};
3+
use objc2::{msg_send, msg_send_bool};
44

55
use super::NSString;
66

@@ -17,8 +17,7 @@ impl NSObject {
1717
}
1818

1919
pub fn is_equal(&self, other: &NSObject) -> bool {
20-
let result: Bool = unsafe { msg_send![self, isEqual: other] };
21-
result.as_bool()
20+
unsafe { msg_send_bool![self, isEqual: other] }
2221
}
2322

2423
pub fn description(&self) -> Id<NSString, Shared> {
@@ -30,8 +29,7 @@ impl NSObject {
3029
}
3130

3231
pub fn is_kind_of(&self, cls: &Class) -> bool {
33-
let result: Bool = unsafe { msg_send![self, isKindOfClass: cls] };
34-
result.as_bool()
32+
unsafe { msg_send_bool![self, isKindOfClass: cls] }
3533
}
3634
}
3735

objc2-foundation/src/string.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ use std::os::raw::c_char;
88

99
use alloc::borrow::ToOwned;
1010
use objc2::ffi;
11-
use objc2::msg_send;
1211
use objc2::rc::DefaultId;
1312
use objc2::rc::{autoreleasepool, AutoreleasePool};
1413
use objc2::rc::{Id, Shared};
15-
use objc2::runtime::{Bool, Class, Object};
14+
use objc2::runtime::{Class, Object};
15+
use objc2::{msg_send, msg_send_bool};
1616

1717
use crate::{NSComparisonResult, NSCopying, NSMutableCopying, NSMutableString, NSObject};
1818

@@ -182,8 +182,7 @@ impl NSString {
182182
#[doc(alias = "hasPrefix")]
183183
#[doc(alias = "hasPrefix:")]
184184
pub fn has_prefix(&self, prefix: &NSString) -> bool {
185-
let res: Bool = unsafe { msg_send![self, hasPrefix: prefix] };
186-
res.is_true()
185+
unsafe { msg_send_bool![self, hasPrefix: prefix] }
187186
}
188187

189188
/// Whether the given string matches the ending characters of this string.
@@ -192,8 +191,7 @@ impl NSString {
192191
#[doc(alias = "hasSuffix")]
193192
#[doc(alias = "hasSuffix:")]
194193
pub fn has_suffix(&self, suffix: &NSString) -> bool {
195-
let res: Bool = unsafe { msg_send![self, hasSuffix: suffix] };
196-
res.is_true()
194+
unsafe { msg_send_bool![self, hasSuffix: suffix] }
197195
}
198196

199197
// pub fn from_nsrange(range: NSRange) -> Id<Self, Shared>

objc2-foundation/src/thread.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
use objc2::msg_send;
21
use objc2::rc::{Id, Shared};
3-
use objc2::runtime::Bool;
2+
use objc2::{msg_send, msg_send_bool};
43

54
use crate::{NSObject, NSString};
65

@@ -34,8 +33,7 @@ impl NSThread {
3433

3534
/// Returns `true` if the thread is the main thread.
3635
pub fn is_main(&self) -> bool {
37-
let res: Bool = unsafe { msg_send![self, isMainThread] };
38-
res.is_true()
36+
unsafe { msg_send_bool![self, isMainThread] }
3937
}
4038

4139
/// The name of the thread.
@@ -47,14 +45,12 @@ impl NSThread {
4745

4846
/// Whether the application is multithreaded according to Cocoa.
4947
pub fn is_multi_threaded() -> bool {
50-
let res: Bool = unsafe { msg_send![NSThread::class(), isMultiThreaded] };
51-
res.is_true()
48+
unsafe { msg_send_bool![NSThread::class(), isMultiThreaded] }
5249
}
5350

5451
/// Whether the current thread is the main thread.
5552
pub fn is_main_thread() -> bool {
56-
let res: Bool = unsafe { msg_send![NSThread::class(), isMainThread] };
57-
res.is_true()
53+
unsafe { msg_send_bool![NSThread::class(), isMainThread] }
5854
}
5955

6056
#[cfg(test)]

objc2/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1515
* The `objc2-encode` dependency is now exposed as `objc2::encode`.
1616
* Added `Id::retain_autoreleased` to allow following Cocoas memory management
1717
rules more efficiently.
18+
* Consistently allow trailing commas in `msg_send!`.
19+
* Added `msg_send_bool!`, a less error-prone version of `msg_send!` for
20+
Objective-C methods that return `BOOL`.
1821

1922
### Changed
2023
* **BREAKING**: Changed signature of `Id::new` and `Id::retain` from

objc2/src/bool.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@ use core::fmt;
1616
/// # Example
1717
///
1818
/// ```no_run
19-
/// use objc2::{class, msg_send};
19+
/// use objc2::{class, msg_send, msg_send_bool};
2020
/// use objc2::runtime::{Object, Bool};
2121
/// let ns_value: *mut Object = unsafe { msg_send![class!(NSValue), initWithBool: Bool::YES] };
22-
/// let rtn: Bool = unsafe { msg_send![ns_value, boolValue] };
23-
/// assert!(rtn.as_bool());
22+
/// assert!(unsafe { msg_send_bool![ns_value, boolValue] });
2423
/// ```
2524
#[repr(transparent)]
2625
// We don't implement comparison traits because they could be implemented with

objc2/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
//!
3030
#![cfg_attr(apple, doc = "```")]
3131
#![cfg_attr(not(apple), doc = "```no_run")]
32-
//! use objc2::{class, msg_send};
32+
//! use objc2::{class, msg_send, msg_send_bool};
3333
//! use objc2::ffi::NSUInteger;
3434
//! use objc2::rc::{Id, Owned};
3535
//! use objc2::runtime::{Bool, Object};
@@ -43,8 +43,8 @@
4343
//!
4444
//! // Usage
4545
//! let hash: NSUInteger = unsafe { msg_send![obj, hash] };
46-
//! let is_kind: Bool = unsafe { msg_send![obj, isKindOfClass: cls] };
47-
//! assert!(is_kind.as_bool());
46+
//! let is_kind = unsafe { msg_send_bool![obj, isKindOfClass: cls] };
47+
//! assert!(is_kind);
4848
//! ```
4949
//!
5050
//! Note that this very simple example contains **a lot** of `unsafe` (which

objc2/src/macros.rs

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,9 @@ macro_rules! class {
4444
/// ```
4545
#[macro_export]
4646
macro_rules! sel {
47-
($name:ident) => ({
47+
($first:ident $(: $($rest:ident :)*)?) => ({
4848
static SEL: $crate::__CachedSel = $crate::__CachedSel::new();
49-
let name = concat!(stringify!($name), '\0');
50-
#[allow(unused_unsafe)]
51-
unsafe { SEL.get(name) }
52-
});
53-
($($name:ident :)+) => ({
54-
static SEL: $crate::__CachedSel = $crate::__CachedSel::new();
55-
let name = concat!($(stringify!($name), ':'),+, '\0');
49+
let name = concat!(stringify!($first), $(':', $(stringify!($rest), ':',)*)? '\0');
5650
#[allow(unused_unsafe)]
5751
unsafe { SEL.get(name) }
5852
});
@@ -135,40 +129,76 @@ macro_rules! sel {
135129
/// [RFC-2945]: https://rust-lang.github.io/rfcs/2945-c-unwind-abi.html
136130
#[macro_export]
137131
macro_rules! msg_send {
138-
(super($obj:expr, $superclass:expr), $name:ident) => ({
139-
let sel = $crate::sel!($name);
132+
[super($obj:expr, $superclass:expr), $selector:ident $(,)?] => ({
133+
let sel = $crate::sel!($selector);
140134
let result;
141135
match $crate::MessageReceiver::send_super_message(&$obj, $superclass, sel, ()) {
142136
Err(s) => panic!("{}", s),
143137
Ok(r) => result = r,
144138
}
145139
result
146140
});
147-
(super($obj:expr, $superclass:expr), $($name:ident : $arg:expr $(,)?)+) => ({
148-
let sel = $crate::sel!($($name:)+);
141+
[super($obj:expr, $superclass:expr), $($selector:ident : $argument:expr $(,)?)+] => ({
142+
let sel = $crate::sel!($($selector :)+);
149143
let result;
150-
match $crate::MessageReceiver::send_super_message(&$obj, $superclass, sel, ($($arg,)+)) {
144+
match $crate::MessageReceiver::send_super_message(&$obj, $superclass, sel, ($($argument,)+)) {
151145
Err(s) => panic!("{}", s),
152146
Ok(r) => result = r,
153147
}
154148
result
155149
});
156-
($obj:expr, $name:ident) => ({
157-
let sel = $crate::sel!($name);
150+
[$obj:expr, $selector:ident $(,)?] => ({
151+
let sel = $crate::sel!($selector);
158152
let result;
159153
match $crate::MessageReceiver::send_message(&$obj, sel, ()) {
160154
Err(s) => panic!("{}", s),
161155
Ok(r) => result = r,
162156
}
163157
result
164158
});
165-
($obj:expr, $($name:ident : $arg:expr $(,)?)+) => ({
166-
let sel = $crate::sel!($($name:)+);
159+
[$obj:expr, $($selector:ident : $argument:expr $(,)?)+] => ({
160+
let sel = $crate::sel!($($selector :)+);
167161
let result;
168-
match $crate::MessageReceiver::send_message(&$obj, sel, ($($arg,)+)) {
162+
match $crate::MessageReceiver::send_message(&$obj, sel, ($($argument,)+)) {
169163
Err(s) => panic!("{}", s),
170164
Ok(r) => result = r,
171165
}
172166
result
173167
});
174168
}
169+
170+
/// A less error-prone version of [`msg_send!`] for methods returning `BOOL`.
171+
///
172+
/// Objective-C's `BOOL` is different from Rust's [`bool`] (see [`Bool`]), so
173+
/// a conversion step must be performed before using it - this macro does that
174+
/// for you!
175+
///
176+
/// [`Bool`]: crate::runtime::Bool
177+
///
178+
/// Equivalent to the following:
179+
///
180+
/// ```ignore
181+
/// # use objc2::msg_send;
182+
/// # use objc2::runtime::Bool;
183+
/// # let obj: *mut Object = 0 as *mut Object;
184+
/// {
185+
/// let result: Bool = msg_send![obj, selector];
186+
/// result.as_bool()
187+
/// };
188+
/// ```
189+
///
190+
/// # Examples
191+
///
192+
/// ```no_run
193+
/// # use objc2::msg_send_bool;
194+
/// # use objc2::runtime::Object;
195+
/// # let obj: *mut Object = 0 as *mut Object;
196+
/// assert!(unsafe { msg_send_bool![obj, isEqual: obj] });
197+
/// ```
198+
#[macro_export]
199+
macro_rules! msg_send_bool {
200+
[$($msg_send_args:tt)+] => ({
201+
let result: $crate::runtime::Bool = $crate::msg_send![$($msg_send_args)+];
202+
result.as_bool()
203+
});
204+
}

objc2/src/runtime.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,7 @@ impl Ivar {
170170

171171
/// Returns the offset of self.
172172
pub fn offset(&self) -> isize {
173-
let offset = unsafe { ffi::ivar_getOffset(self.as_ptr()) };
174-
offset as isize
173+
unsafe { ffi::ivar_getOffset(self.as_ptr()) }
175174
}
176175

177176
/// Returns the `Encoding` of self.
@@ -627,6 +626,7 @@ mod tests {
627626
test_sel!("abc", abc);
628627
test_sel!("abc:", abc:);
629628
test_sel!("abc:def:", abc:def:);
629+
test_sel!("abc:def:ghi:", abc:def:ghi:);
630630
}
631631

632632
#[test]

objc2/tests/use_macros.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use objc2::runtime::Object;
1+
use objc2::runtime::{Class, Object};
22
use objc2::{class, msg_send, sel};
33

44
#[cfg(gnustep)]
@@ -22,3 +22,28 @@ fn use_sel() {
2222
let _sel = sel!(description);
2323
let _sel = sel!(setObject:forKey:);
2424
}
25+
26+
#[allow(unused)]
27+
fn test_msg_send_comma_handling(obj: &Object, superclass: &Class) {
28+
unsafe {
29+
let _: () = msg_send![obj, a];
30+
let _: () = msg_send![obj, a,];
31+
let _: () = msg_send![obj, a: 32i32];
32+
let _: () = msg_send![obj, a: 32i32,];
33+
let _: () = msg_send![obj, a: 32i32 b: 32i32];
34+
let _: () = msg_send![obj, a: 32i32 b: 32i32,];
35+
let _: () = msg_send![obj, a: 32i32, b: 32i32];
36+
let _: () = msg_send![obj, a: 32i32, b: 32i32,];
37+
}
38+
39+
unsafe {
40+
let _: () = msg_send![super(obj, superclass), a];
41+
let _: () = msg_send![super(obj, superclass), a,];
42+
let _: () = msg_send![super(obj, superclass), a: 32i32];
43+
let _: () = msg_send![super(obj, superclass), a: 32i32,];
44+
let _: () = msg_send![super(obj, superclass), a: 32i32 b: 32i32];
45+
let _: () = msg_send![super(obj, superclass), a: 32i32 b: 32i32,];
46+
let _: () = msg_send![super(obj, superclass), a: 32i32, b: 32i32];
47+
let _: () = msg_send![super(obj, superclass), a: 32i32, b: 32i32,];
48+
}
49+
}

tests/ui/invalid_msg_send.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//! Test invalid msg_send syntax
2+
use objc2::msg_send;
3+
use objc2::runtime::Object;
4+
5+
fn main() {
6+
let obj: &Object;
7+
let b = 32i32;
8+
let d = 32i32;
9+
let _: () = unsafe { msg_send![obj] };
10+
let _: () = unsafe { msg_send![obj,] };
11+
let _: () = unsafe { msg_send![obj, a:] };
12+
let _: () = unsafe { msg_send![obj, a: b c] };
13+
let _: () = unsafe { msg_send![obj, a: b: c] };
14+
let _: () = unsafe { msg_send![obj, a: b, c d] };
15+
let _: () = unsafe { msg_send![obj, a: b: c] };
16+
}

0 commit comments

Comments
 (0)