Skip to content
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

Add support for this marking an instance method in extern_methods! #281

Merged
merged 1 commit into from
Nov 1, 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
3 changes: 3 additions & 0 deletions objc2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Verify in `declare_class!` that protocols are implemented correctly.
* **BREAKING**: Changed the name of the attribute macro in `extern_methods`
from `#[sel(...)]` to `#[method(...)]`.
* **BREAKING**: Changed `extern_methods!` and `declare_class!` such that
associated functions whoose first parameter is called `this`, is treated as
instance methods instead of class methods.


## 0.3.0-beta.3 - 2022-09-01
Expand Down
68 changes: 68 additions & 0 deletions objc2/src/macros/__rewrite_self_arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,74 @@ macro_rules! __rewrite_self_arg {
}
};

// `this: Type` or `_this: Type` instance method
// Workaround for arbitary self types being unstable
// https://doc.rust-lang.org/nightly/unstable-book/language-features/arbitrary-self-types.html
{
($out_macro:path)
@(mut this: $__self_ty:ty $(, $($__rest_args:tt)*)?)
@(mut $this:ident: $this_ty:ty $(, $($rest:tt)*)?)
$($macro_args:tt)*
} => {
$out_macro! {
$($macro_args)*
@(instance_method)
@(
mut $this: $this_ty,
_: $crate::runtime::Sel,
)
@($($($rest)*)?)
}
};
{
($out_macro:path)
@(this: $__self_ty:ty $(, $($__rest_args:tt)*)?)
@($this:ident: $this_ty:ty $(, $($rest:tt)*)?)
$($macro_args:tt)*
} => {
$out_macro! {
$($macro_args)*
@(instance_method)
@(
$this: $this_ty,
_: $crate::runtime::Sel,
)
@($($($rest)*)?)
}
};
{
($out_macro:path)
@(mut _this: $__self_ty:ty $(, $($__rest_args:tt)*)?)
@(mut $this:ident: $this_ty:ty $(, $($rest:tt)*)?)
$($macro_args:tt)*
} => {
$out_macro! {
$($macro_args)*
@(instance_method)
@(
mut $this: $this_ty,
_: $crate::runtime::Sel,
)
@($($($rest)*)?)
}
};
{
($out_macro:path)
@(_this: $__self_ty:ty $(, $($__rest_args:tt)*)?)
@($this:ident: $this_ty:ty $(, $($rest:tt)*)?)
$($macro_args:tt)*
} => {
$out_macro! {
$($macro_args)*
@(instance_method)
@(
$this: $this_ty,
_: $crate::runtime::Sel,
)
@($($($rest)*)?)
}
};

// Class method
{
($out_macro:path)
Expand Down
9 changes: 5 additions & 4 deletions objc2/src/macros/declare_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@
/// Within the `impl` block you can define two types of functions;
/// ["associated functions"] and ["methods"]. These are then mapped to the
/// Objective-C equivalents "class methods" and "instance methods". In
/// particular, if you use `self` your method will be registered as an
/// instance method, and if you don't it will be registered as a class method.
/// particular, if you use `self` or the special name `this` (or `_this`),
/// your method will be registered as an instance method, and if you don't it
/// will be registered as a class method.
///
/// The desired selector can be specified using the `#[method(my:selector:)]`
/// attribute, similar to the [`extern_methods!`] macro.
Expand Down Expand Up @@ -140,9 +141,9 @@
///
/// unsafe impl MyCustomObject {
/// #[method(initWithFoo:)]
/// fn init_with(&mut self, foo: u8) -> Option<&mut Self> {
/// fn init_with(this: &mut Self, foo: u8) -> Option<&mut Self> {
/// let this: Option<&mut Self> = unsafe {
/// msg_send![super(self), init]
/// msg_send![super(this), init]
/// };
///
/// // TODO: `ns_string` can't be used inside closures.
Expand Down
29 changes: 20 additions & 9 deletions objc2/src/macros/extern_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
/// Within the `impl` block you can define two types of functions without
/// bodies; ["associated functions"] and ["methods"]. These are then mapped to
/// the Objective-C equivalents "class methods" and "instance methods", and an
/// appropriate body is created for you. In particular, if you use `self` your
/// method will assumbed to be an instance method, and if you don't it will be
/// assumed to be a class method.
/// appropriate body is created for you. In particular, if you use `self` or
/// the special name `this` (or `_this`), your method will assumed to be an
/// instance method, and if you don't it will be assumed to be a class method.
///
/// The desired selector can be specified using the `#[method(my:selector:)]`
/// attribute. The name of the function doesn't matter.
/// attribute. The name of the function doesn't matter for out purposes, but
/// is of course what the user will use to access the functionality.
///
/// If you specify a function/method with a body, the macro will simply ignore
/// it.
Expand Down Expand Up @@ -102,8 +103,14 @@
/// // passed.
/// pub unsafe fn date_matches(&self, date: &NSObject, components: &NSObject) -> bool;
///
/// #[method(minimumRangeOfUnit:)]
/// pub fn min_range(&self, unit: NSCalendarUnit) -> NSRange;
///
/// #[method(maximumRangeOfUnit:)]
/// pub fn max_range(&self, unit: NSCalendarUnit) -> NSRange;
/// // Arbitary self types are not stable, but we can work around it
/// // with the special name `this`. In this case, it is `unsafe`
/// // because the self type is a pointer instead of a reference.
/// pub unsafe fn max_range(this: *const Self, unit: NSCalendarUnit) -> NSRange;
///
/// // From `NSKeyValueCoding`
/// #[method(validateValue:forKey:error:)]
Expand Down Expand Up @@ -183,8 +190,12 @@
/// unsafe { msg_send![self, date: date, matchesComponents: components] }
/// }
///
/// pub fn max_range(&self, unit: NSCalendarUnit) -> NSRange {
/// unsafe { msg_send![self, maximumRangeOfUnit: unit] }
/// pub fn min_range(&self, unit: NSCalendarUnit) -> NSRange {
/// unsafe { msg_send![self, minimumRangeOfUnit: unit] }
/// }
///
/// pub fn max_range(this: *const Self, unit: NSCalendarUnit) -> NSRange {
/// unsafe { msg_send![this, maximumRangeOfUnit: unit] }
/// }
///
/// pub unsafe fn validate_value_for_key(
Expand Down Expand Up @@ -333,15 +344,15 @@ macro_rules! __inner_extern_methods {
@unsafe_method_body
@(instance_method)
@(
$self:ident: $self_ty:ty,
$self_or_this:ident: $self_or_this_ty:ty,
_: $sel_ty:ty,
)
@($($args_rest:tt)*)
@($($sel:tt)*)
} => {
$crate::__collect_msg_send! {
$crate::msg_send;
$self;
$self_or_this;
($($sel)*);
($($args_rest)*);
}
Expand Down
16 changes: 8 additions & 8 deletions objc2/src/rc/test_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ declare_class!(
}

#[method(init)]
fn init(&mut self) -> *mut Self {
fn init(this: &mut Self) -> *mut Self {
TEST_DATA.with(|data| data.borrow_mut().init += 1);
unsafe { msg_send![super(self), init] }
unsafe { msg_send![super(this), init] }
}

#[method(initReturningNull)]
Expand Down Expand Up @@ -153,12 +153,12 @@ declare_class!(
}

#[method(copyReturningNull)]
fn copy_returning_null(&self) -> *const Self {
fn copy_returning_null(_this: &Self) -> *const Self {
ptr::null()
}

#[method(methodReturningNull)]
fn method_returning_null(&self) -> *const Self {
fn method_returning_null(self: &Self) -> *const Self {
ptr::null()
}

Expand Down Expand Up @@ -207,7 +207,7 @@ declare_class!(

#[method(idAndShouldError:error:)]
fn instance_error_id(
&self,
self: &Self,
should_error: bool,
err: Option<&mut *mut RcTestObject>,
) -> *mut RcTestObject {
Expand Down Expand Up @@ -247,18 +247,18 @@ declare_class!(

#[method(initAndShouldError:error:)]
fn init_error(
&mut self,
this: &mut Self,
should_error: bool,
err: Option<&mut *mut RcTestObject>,
) -> *mut Self {
if should_error {
if let Some(err) = err {
*err = RcTestObject::new().autorelease_inner();
}
let _: () = unsafe { msg_send![self, release] };
let _: () = unsafe { msg_send![this, release] };
ptr::null_mut()
} else {
unsafe { msg_send![self, init] }
unsafe { msg_send![this, init] }
}
}
}
Expand Down
14 changes: 14 additions & 0 deletions test-ui/ui/extern_methods_wrong_arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,18 @@ extern_methods!(
}
);

extern_methods!(
unsafe impl MyObject {
#[method(z:)]
fn z(this: &Self);
}
);

extern_methods!(
unsafe impl MyObject {
#[method(w)]
fn w(this: &Self, arg: i32);
}
);

fn main() {}
31 changes: 31 additions & 0 deletions test-ui/ui/extern_methods_wrong_arguments.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,19 @@ error: Number of arguments in function and selector did not match!
|
= note: this error originates in the macro `$crate::__collect_msg_send` which comes from the expansion of the macro `extern_methods` (in Nightly builds, run with -Z macro-backtrace for more info)

error: Number of arguments in function and selector did not match!
--> ui/extern_methods_wrong_arguments.rs
|
| / extern_methods!(
| | unsafe impl MyObject {
| | #[method(w)]
| | fn w(this: &Self, arg: i32);
| | }
| | );
| |_^
|
= note: this error originates in the macro `$crate::__collect_msg_send` which comes from the expansion of the macro `extern_methods` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: mismatched types
--> ui/extern_methods_wrong_arguments.rs
|
Expand Down Expand Up @@ -90,3 +103,21 @@ error[E0308]: mismatched types
= note: expected unit type `()`
found enum `Result<(), Id<_, Shared>>`
= note: this error originates in the macro `$crate::__msg_send_helper` which comes from the expansion of the macro `extern_methods` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: mismatched types
--> ui/extern_methods_wrong_arguments.rs
|
| / extern_methods!(
| | unsafe impl MyObject {
| | #[method(z:)]
| | fn z(this: &Self);
| | }
| | );
| | ^
| | |
| |_expected `()`, found enum `Result`
| expected `()` because of default return type
|
= note: expected unit type `()`
found enum `Result<(), Id<_, Shared>>`
= note: this error originates in the macro `$crate::__msg_send_helper` which comes from the expansion of the macro `extern_methods` (in Nightly builds, run with -Z macro-backtrace for more info)