Skip to content

Add msg_send_bool! #147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions objc2-foundation/src/object.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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<NSString, Shared> {
Expand All @@ -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] }
}
}

Expand Down
10 changes: 4 additions & 6 deletions objc2-foundation/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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.
Expand All @@ -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<Self, Shared>
Expand Down
12 changes: 4 additions & 8 deletions objc2-foundation/src/thread.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down Expand Up @@ -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.
Expand All @@ -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)]
Expand Down
3 changes: 3 additions & 0 deletions objc2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ 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!`.
* 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
Expand Down
5 changes: 2 additions & 3 deletions objc2/src/bool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions objc2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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
Expand Down
66 changes: 48 additions & 18 deletions objc2/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
});
Expand Down Expand Up @@ -135,40 +129,76 @@ 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),
Ok(r) => result = r,
}
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),
Ok(r) => result = r,
}
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,
}
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()
});
}
4 changes: 2 additions & 2 deletions objc2/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -627,6 +626,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]
Expand Down
27 changes: 26 additions & 1 deletion objc2/tests/use_macros.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use objc2::runtime::Object;
use objc2::runtime::{Class, Object};
use objc2::{class, msg_send, sel};

#[cfg(gnustep)]
Expand All @@ -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,];
}
}
16 changes: 16 additions & 0 deletions tests/ui/invalid_msg_send.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//! 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:] };
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] };
}
41 changes: 41 additions & 0 deletions tests/ui/invalid_msg_send.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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: unexpected end of macro invocation
--> ui/invalid_msg_send.rs:11:43
|
11 | let _: () = unsafe { msg_send![obj, a:] };
| ^ missing tokens in macro arguments

error: unexpected end of macro invocation
--> ui/invalid_msg_send.rs:12:47
|
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:14:49
|
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:13:47
|
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:15:47
|
15 | let _: () = unsafe { msg_send![obj, a: b: c] };
| ^ expecting a type here because of type ascription
14 changes: 14 additions & 0 deletions tests/ui/invalid_msg_send_super.rs
Original file line number Diff line number Diff line change
@@ -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] };
}
Loading