diff --git a/objc2/CHANGELOG.md b/objc2/CHANGELOG.md index c7a7ea98e..51bd8ff27 100644 --- a/objc2/CHANGELOG.md +++ b/objc2/CHANGELOG.md @@ -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 diff --git a/objc2/examples/delegate.rs b/objc2/examples/delegate.rs index f741b8636..a0dc2c88c 100644 --- a/objc2/examples/delegate.rs +++ b/objc2/examples/delegate.rs @@ -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"))] @@ -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 } diff --git a/objc2/src/macros/declare_class.rs b/objc2/src/macros/declare_class.rs index dfe649e69..844640b04 100644 --- a/objc2/src/macros/declare_class.rs +++ b/objc2/src/macros/declare_class.rs @@ -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>::__Encode { + $($body_prefix)* + <$ret as $crate::encode::EncodeConvert>::__into_encode($($body)*) + }) } }; @@ -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>::__Encode,) + ( + $($body_prefix)* + let mut $param = <$param_ty as $crate::encode::EncodeConvert>::__from_encode($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>::__Encode,) + ( + $($body_prefix)* + let $param = <$param_ty as $crate::encode::EncodeConvert>::__from_encode($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 @@ -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 @@ -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")] @@ -290,8 +423,8 @@ macro_rules! __fn_ptr { /// } /// /// #[sel(myClassMethod)] -/// fn __my_class_method() -> Bool { -/// Bool::YES +/// fn __my_class_method() -> bool { +/// true /// } /// } /// diff --git a/objc2/src/rc/test_object.rs b/objc2/src/rc/test_object.rs index fbcc9132e..f6a05da6d 100644 --- a/objc2/src/rc/test_object.rs +++ b/objc2/src/rc/test_object.rs @@ -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)] @@ -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:)]