Skip to content

Commit dee955d

Browse files
committed
Support bool arguments/return type in declare_class!
1 parent 0490fc1 commit dee955d

File tree

4 files changed

+144
-12
lines changed

4 files changed

+144
-12
lines changed

objc2/CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
2424
* Added ability to call `msg_send![super(obj), ...]` without explicitly
2525
specifying the superclass.
2626
* Added automatic conversion of `bool` to/from the Objective-C `BOOL` in
27-
`msg_send!`, `msg_send_id!` and `extern_methods!`.
27+
`msg_send!`, `msg_send_id!`, `extern_methods!` and `declare_class!`.
2828

2929
Example:
3030
```rust

objc2/examples/delegate.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![cfg_attr(not(all(feature = "apple", target_os = "macos")), allow(unused))]
22
use objc2::foundation::NSObject;
33
use objc2::rc::{Id, Shared};
4-
use objc2::runtime::{Bool, Object};
4+
use objc2::runtime::Object;
55
use objc2::{declare_class, extern_class, msg_send, msg_send_id, ClassType};
66

77
#[cfg(all(feature = "apple", target_os = "macos"))]
@@ -31,12 +31,12 @@ declare_class!(
3131

3232
unsafe impl CustomAppDelegate {
3333
#[sel(initWith:another:)]
34-
fn init_with(self: &mut Self, ivar: u8, another_ivar: Bool) -> *mut Self {
34+
fn init_with(self: &mut Self, ivar: u8, another_ivar: bool) -> *mut Self {
3535
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;
39-
*this.another_ivar = another_ivar.as_bool();
39+
*this.another_ivar = another_ivar;
4040
}
4141
this
4242
}

objc2/src/macros/declare_class.rs

+138-5
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,67 @@ macro_rules! __inner_declare_class {
7777
@($($_kind:tt)*)
7878
@($($args_start:tt)*)
7979
@($($args_rest:tt)*)
80+
} => {
81+
$crate::__fn_args! {
82+
($crate::__inner_declare_class)
83+
($($args_rest)*,)
84+
()
85+
()
86+
@method_out_inner
87+
@($(#[$($m)*])*)
88+
@($($qualifiers)*)
89+
@($name)
90+
@($($ret)?)
91+
@($($body)*)
92+
@($($_kind)*)
93+
@($($args_start)*)
94+
// Will add @(args_converted)
95+
// Will add @(body_prefix)
96+
}
97+
};
98+
99+
// No return type
100+
{
101+
@method_out_inner
102+
@($(#[$($m:tt)*])*)
103+
@($($qualifiers:tt)*)
104+
@($name:ident)
105+
@()
106+
@($($body:tt)*)
107+
@($($_kind:tt)*)
108+
@($($args_start:tt)*)
109+
@($($args_converted:tt)*)
110+
@($($body_prefix:tt)*)
80111
} => {
81112
$crate::__attribute_helper! {
82113
@strip_sel
83114
$(@[$($m)*])*
84-
($($qualifiers)* fn $name($($args_start)* $($args_rest)*) $(-> $ret)? $($body)*)
115+
($($qualifiers)* fn $name($($args_start)* $($args_converted)*) {
116+
$($body_prefix)*
117+
$($body)*
118+
})
119+
}
120+
};
121+
// With return type
122+
{
123+
@method_out_inner
124+
@($(#[$($m:tt)*])*)
125+
@($($qualifiers:tt)*)
126+
@($name:ident)
127+
@($ret:ty)
128+
@($($body:tt)*)
129+
@($($_kind:tt)*)
130+
@($($args_start:tt)*)
131+
@($($args_converted:tt)*)
132+
@($($body_prefix:tt)*)
133+
} => {
134+
$crate::__attribute_helper! {
135+
@strip_sel
136+
$(@[$($m)*])*
137+
($($qualifiers)* fn $name($($args_start)* $($args_converted)*) -> <$ret as $crate::encode::EncodeConvert>::__Inner {
138+
$($body_prefix)*
139+
<$ret as $crate::encode::EncodeConvert>::__into_inner($($body)*)
140+
})
85141
}
86142
};
87143

@@ -146,13 +202,86 @@ macro_rules! __inner_declare_class {
146202
macro_rules! __fn_ptr {
147203
(
148204
@($($qualifiers:tt)*)
149-
$($($param:ident)? $(_)?: $param_ty:ty),* $(,)?
205+
$($(mut)? $($param:ident)? $(_)?: $param_ty:ty),* $(,)?
150206
) => {
151207
$($qualifiers)* fn($($crate::__fn_ptr!(@__to_anonymous $param_ty)),*) -> _
152208
};
153209
(@__to_anonymous $param_ty:ty) => { _ }
154210
}
155211

212+
#[doc(hidden)]
213+
#[macro_export]
214+
macro_rules! __fn_args {
215+
// Ignore `_`
216+
{
217+
($out_macro:path)
218+
(_: $param_ty:ty, $($rest:tt)*)
219+
($($args_converted:tt)*)
220+
($($body_prefix:tt)*)
221+
$($macro_args:tt)*
222+
} => {
223+
$crate::__fn_args! {
224+
($out_macro)
225+
($($rest)*)
226+
($($args_converted)* _: $param_ty,)
227+
($($body_prefix)*)
228+
$($macro_args)*
229+
}
230+
};
231+
// Convert mut
232+
{
233+
($out_macro:path)
234+
(mut $param:ident: $param_ty:ty, $($rest:tt)*)
235+
($($args_converted:tt)*)
236+
($($body_prefix:tt)*)
237+
$($macro_args:tt)*
238+
} => {
239+
$crate::__fn_args! {
240+
($out_macro)
241+
($($rest)*)
242+
($($args_converted)* $param: <$param_ty as $crate::encode::EncodeConvert>::__Inner,)
243+
(
244+
$($body_prefix)*
245+
let mut $param = <$param_ty as $crate::encode::EncodeConvert>::__from_inner($param);
246+
)
247+
$($macro_args)*
248+
}
249+
};
250+
// Convert
251+
{
252+
($out_macro:path)
253+
($param:ident: $param_ty:ty, $($rest:tt)*)
254+
($($args_converted:tt)*)
255+
($($body_prefix:tt)*)
256+
$($macro_args:tt)*
257+
} => {
258+
$crate::__fn_args! {
259+
($out_macro)
260+
($($rest)*)
261+
($($args_converted)* $param: <$param_ty as $crate::encode::EncodeConvert>::__Inner,)
262+
(
263+
$($body_prefix)*
264+
let $param = <$param_ty as $crate::encode::EncodeConvert>::__from_inner($param);
265+
)
266+
$($macro_args)*
267+
}
268+
};
269+
// Output result
270+
{
271+
($out_macro:path)
272+
($(,)*)
273+
($($args_converted:tt)*)
274+
($($body_prefix:tt)*)
275+
$($macro_args:tt)*
276+
} => {
277+
$out_macro! {
278+
$($macro_args)*
279+
@($($args_converted)*)
280+
@($($body_prefix)*)
281+
}
282+
};
283+
}
284+
156285
/// Declare a new Objective-C class.
157286
///
158287
/// This is mostly just a convenience macro on top of [`extern_class!`] and
@@ -205,10 +334,15 @@ macro_rules! __fn_ptr {
205334
/// can't mark them as `pub` for the same reason). Instead, use the
206335
/// [`extern_methods!`] macro to create a Rust interface to the methods.
207336
///
337+
/// If the argument or return type is [`bool`], a conversion is performed to
338+
/// make it behave similarly to the Objective-C `BOOL`. Use [`runtime::Bool`]
339+
/// if you want to control this manually.
340+
///
208341
/// ["associated functions"]: https://doc.rust-lang.org/reference/items/associated-items.html#methods
209342
/// ["methods"]: https://doc.rust-lang.org/reference/items/associated-items.html#methods
210343
/// [`extern_methods!`]: crate::extern_methods
211344
/// [`msg_send!`]: crate::msg_send
345+
/// [`runtime::Bool`]: crate::runtime::Bool
212346
///
213347
///
214348
/// ## Protocol definitions
@@ -252,7 +386,6 @@ macro_rules! __fn_ptr {
252386
/// use std::os::raw::c_int;
253387
/// use objc2::rc::{Id, Owned};
254388
/// use objc2::foundation::{NSCopying, NSObject, NSZone};
255-
/// use objc2::runtime::Bool;
256389
/// use objc2::{declare_class, msg_send, msg_send_id, ClassType};
257390
/// #
258391
/// # #[cfg(feature = "gnustep-1-7")]
@@ -290,8 +423,8 @@ macro_rules! __fn_ptr {
290423
/// }
291424
///
292425
/// #[sel(myClassMethod)]
293-
/// fn __my_class_method() -> Bool {
294-
/// Bool::YES
426+
/// fn __my_class_method() -> bool {
427+
/// true
295428
/// }
296429
/// }
297430
///

objc2/src/rc/test_object.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use core::ptr;
44

55
use super::{Id, Owned};
66
use crate::foundation::{NSObject, NSZone};
7-
use crate::runtime::Bool;
87
use crate::{declare_class, msg_send, ClassType};
98

109
#[derive(Debug, Clone, Default, PartialEq, Eq)]
@@ -120,14 +119,14 @@ declare_class!(
120119
}
121120

122121
#[sel(_tryRetain)]
123-
unsafe fn try_retain(&self) -> Bool {
122+
unsafe fn try_retain(&self) -> bool {
124123
TEST_DATA.with(|data| data.borrow_mut().try_retain += 1);
125124
let res: bool = unsafe { msg_send![super(self), _tryRetain] };
126125
if !res {
127126
TEST_DATA.with(|data| data.borrow_mut().try_retain -= 1);
128127
TEST_DATA.with(|data| data.borrow_mut().try_retain_fail += 1);
129128
}
130-
Bool::new(res)
129+
res
131130
}
132131

133132
#[sel(copyWithZone:)]

0 commit comments

Comments
 (0)