Skip to content

Commit

Permalink
Support bool arguments/return type in declare_class!
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Aug 28, 2022
1 parent 0490fc1 commit dee955d
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 12 deletions.
2 changes: 1 addition & 1 deletion objc2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Added ability to call `msg_send![super(obj), ...]` without explicitly
specifying the superclass.
* Added automatic conversion of `bool` to/from the Objective-C `BOOL` in
`msg_send!`, `msg_send_id!` and `extern_methods!`.
`msg_send!`, `msg_send_id!`, `extern_methods!` and `declare_class!`.

Example:
```rust
Expand Down
6 changes: 3 additions & 3 deletions objc2/examples/delegate.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![cfg_attr(not(all(feature = "apple", target_os = "macos")), allow(unused))]
use objc2::foundation::NSObject;
use objc2::rc::{Id, Shared};
use objc2::runtime::{Bool, Object};
use objc2::runtime::Object;
use objc2::{declare_class, extern_class, msg_send, msg_send_id, ClassType};

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

unsafe impl CustomAppDelegate {
#[sel(initWith:another:)]
fn init_with(self: &mut Self, ivar: u8, another_ivar: Bool) -> *mut Self {
fn init_with(self: &mut Self, ivar: u8, another_ivar: bool) -> *mut Self {
let this: *mut Self = unsafe { msg_send![super(self), init] };
if let Some(this) = unsafe { this.as_mut() } {
// TODO: Allow initialization through MaybeUninit
*this.ivar = ivar;
*this.another_ivar = another_ivar.as_bool();
*this.another_ivar = another_ivar;
}
this
}
Expand Down
143 changes: 138 additions & 5 deletions objc2/src/macros/declare_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,67 @@ macro_rules! __inner_declare_class {
@($($_kind:tt)*)
@($($args_start:tt)*)
@($($args_rest:tt)*)
} => {
$crate::__fn_args! {
($crate::__inner_declare_class)
($($args_rest)*,)
()
()
@method_out_inner
@($(#[$($m)*])*)
@($($qualifiers)*)
@($name)
@($($ret)?)
@($($body)*)
@($($_kind)*)
@($($args_start)*)
// Will add @(args_converted)
// Will add @(body_prefix)
}
};

// No return type
{
@method_out_inner
@($(#[$($m:tt)*])*)
@($($qualifiers:tt)*)
@($name:ident)
@()
@($($body:tt)*)
@($($_kind:tt)*)
@($($args_start:tt)*)
@($($args_converted:tt)*)
@($($body_prefix:tt)*)
} => {
$crate::__attribute_helper! {
@strip_sel
$(@[$($m)*])*
($($qualifiers)* fn $name($($args_start)* $($args_rest)*) $(-> $ret)? $($body)*)
($($qualifiers)* fn $name($($args_start)* $($args_converted)*) {
$($body_prefix)*
$($body)*
})
}
};
// With return type
{
@method_out_inner
@($(#[$($m:tt)*])*)
@($($qualifiers:tt)*)
@($name:ident)
@($ret:ty)
@($($body:tt)*)
@($($_kind:tt)*)
@($($args_start:tt)*)
@($($args_converted:tt)*)
@($($body_prefix:tt)*)
} => {
$crate::__attribute_helper! {
@strip_sel
$(@[$($m)*])*
($($qualifiers)* fn $name($($args_start)* $($args_converted)*) -> <$ret as $crate::encode::EncodeConvert>::__Inner {
$($body_prefix)*
<$ret as $crate::encode::EncodeConvert>::__into_inner($($body)*)
})
}
};

Expand Down Expand Up @@ -146,13 +202,86 @@ macro_rules! __inner_declare_class {
macro_rules! __fn_ptr {
(
@($($qualifiers:tt)*)
$($($param:ident)? $(_)?: $param_ty:ty),* $(,)?
$($(mut)? $($param:ident)? $(_)?: $param_ty:ty),* $(,)?
) => {
$($qualifiers)* fn($($crate::__fn_ptr!(@__to_anonymous $param_ty)),*) -> _
};
(@__to_anonymous $param_ty:ty) => { _ }
}

#[doc(hidden)]
#[macro_export]
macro_rules! __fn_args {
// Ignore `_`
{
($out_macro:path)
(_: $param_ty:ty, $($rest:tt)*)
($($args_converted:tt)*)
($($body_prefix:tt)*)
$($macro_args:tt)*
} => {
$crate::__fn_args! {
($out_macro)
($($rest)*)
($($args_converted)* _: $param_ty,)
($($body_prefix)*)
$($macro_args)*
}
};
// Convert mut
{
($out_macro:path)
(mut $param:ident: $param_ty:ty, $($rest:tt)*)
($($args_converted:tt)*)
($($body_prefix:tt)*)
$($macro_args:tt)*
} => {
$crate::__fn_args! {
($out_macro)
($($rest)*)
($($args_converted)* $param: <$param_ty as $crate::encode::EncodeConvert>::__Inner,)
(
$($body_prefix)*
let mut $param = <$param_ty as $crate::encode::EncodeConvert>::__from_inner($param);
)
$($macro_args)*
}
};
// Convert
{
($out_macro:path)
($param:ident: $param_ty:ty, $($rest:tt)*)
($($args_converted:tt)*)
($($body_prefix:tt)*)
$($macro_args:tt)*
} => {
$crate::__fn_args! {
($out_macro)
($($rest)*)
($($args_converted)* $param: <$param_ty as $crate::encode::EncodeConvert>::__Inner,)
(
$($body_prefix)*
let $param = <$param_ty as $crate::encode::EncodeConvert>::__from_inner($param);
)
$($macro_args)*
}
};
// Output result
{
($out_macro:path)
($(,)*)
($($args_converted:tt)*)
($($body_prefix:tt)*)
$($macro_args:tt)*
} => {
$out_macro! {
$($macro_args)*
@($($args_converted)*)
@($($body_prefix)*)
}
};
}

/// Declare a new Objective-C class.
///
/// This is mostly just a convenience macro on top of [`extern_class!`] and
Expand Down Expand Up @@ -205,10 +334,15 @@ macro_rules! __fn_ptr {
/// can't mark them as `pub` for the same reason). Instead, use the
/// [`extern_methods!`] macro to create a Rust interface to the methods.
///
/// If the argument or return type is [`bool`], a conversion is performed to
/// make it behave similarly to the Objective-C `BOOL`. Use [`runtime::Bool`]
/// if you want to control this manually.
///
/// ["associated functions"]: https://doc.rust-lang.org/reference/items/associated-items.html#methods
/// ["methods"]: https://doc.rust-lang.org/reference/items/associated-items.html#methods
/// [`extern_methods!`]: crate::extern_methods
/// [`msg_send!`]: crate::msg_send
/// [`runtime::Bool`]: crate::runtime::Bool
///
///
/// ## Protocol definitions
Expand Down Expand Up @@ -252,7 +386,6 @@ macro_rules! __fn_ptr {
/// use std::os::raw::c_int;
/// use objc2::rc::{Id, Owned};
/// use objc2::foundation::{NSCopying, NSObject, NSZone};
/// use objc2::runtime::Bool;
/// use objc2::{declare_class, msg_send, msg_send_id, ClassType};
/// #
/// # #[cfg(feature = "gnustep-1-7")]
Expand Down Expand Up @@ -290,8 +423,8 @@ macro_rules! __fn_ptr {
/// }
///
/// #[sel(myClassMethod)]
/// fn __my_class_method() -> Bool {
/// Bool::YES
/// fn __my_class_method() -> bool {
/// true
/// }
/// }
///
Expand Down
5 changes: 2 additions & 3 deletions objc2/src/rc/test_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use core::ptr;

use super::{Id, Owned};
use crate::foundation::{NSObject, NSZone};
use crate::runtime::Bool;
use crate::{declare_class, msg_send, ClassType};

#[derive(Debug, Clone, Default, PartialEq, Eq)]
Expand Down Expand Up @@ -120,14 +119,14 @@ declare_class!(
}

#[sel(_tryRetain)]
unsafe fn try_retain(&self) -> Bool {
unsafe fn try_retain(&self) -> bool {
TEST_DATA.with(|data| data.borrow_mut().try_retain += 1);
let res: bool = unsafe { msg_send![super(self), _tryRetain] };
if !res {
TEST_DATA.with(|data| data.borrow_mut().try_retain -= 1);
TEST_DATA.with(|data| data.borrow_mut().try_retain_fail += 1);
}
Bool::new(res)
res
}

#[sel(copyWithZone:)]
Expand Down

0 comments on commit dee955d

Please sign in to comment.