Skip to content

Make Class no longer implement Message directly #155

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 1 commit into from
Jun 6, 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 @@ -58,6 +58,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

If you previously used `*mut Object` or `&Object` as the receiver, message
sending should work exactly as before.
* **BREAKING**: `Class` no longer implements `Message` (but it can still be
used as the receiver in `msg_send!`, so this is unlikely to break anything
in practice).

### Fixed
* Properly sealed the `MessageArguments` trait (it already had a hidden
Expand Down
23 changes: 21 additions & 2 deletions objc2/src/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use crate::{ffi, Encode, EncodeArguments, Encoding, Message};
/// Types that can be used as the implementation of an Objective-C method.
pub trait MethodImplementation {
/// The callee type of the method.
type Callee: Message + ?Sized;
type Callee: ?Sized;
/// The return type of the method.
type Ret: Encode;
/// The argument types of the method.
Expand All @@ -75,13 +75,32 @@ macro_rules! method_decl_impl {
}
}
);
(@$s:ident, $r:ident, $f:ty, $($t:ident),*) => (
impl<$r, $($t),*> MethodImplementation for $f
where
$r: Encode,
$($t: Encode,)*
{
type Callee = $s;
type Ret = $r;
type Args = ($($t,)*);

fn imp(self) -> Imp {
unsafe { mem::transmute(self) }
}
}
);
($($t:ident),*) => (
method_decl_impl!(-T, R, extern "C" fn(&T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(-T, R, extern "C" fn(&mut T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(-T, R, unsafe extern "C" fn(*const T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(-T, R, unsafe extern "C" fn(*mut T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(-T, R, unsafe extern "C" fn(&T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(-T, R, unsafe extern "C" fn(&mut T, Sel $(, $t)*) -> R, $($t),*);

method_decl_impl!(@Class, R, extern "C" fn(&Class, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(@Class, R, unsafe extern "C" fn(*const Class, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(@Class, R, unsafe extern "C" fn(&Class, Sel $(, $t)*) -> R, $($t),*);
);
}

Expand Down Expand Up @@ -200,7 +219,7 @@ impl ClassBuilder {
/// when the method is invoked from Objective-C.
pub unsafe fn add_method<T, F>(&mut self, sel: Sel, func: F)
where
T: Message + ?Sized, // TODO: Disallow `Class`
T: Message + ?Sized,
F: MethodImplementation<Callee = T>,
{
let encs = F::Args::ENCODINGS;
Expand Down
26 changes: 22 additions & 4 deletions objc2/src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ use self::verify::{verify_message_signature, VerificationError};

/// Types that can be sent Objective-C messages.
///
/// Examples include objects, classes, and blocks.
///
/// Implementing this provides [`MessageReceiver`] implementations for common
/// pointer types and references to the type, which allows using them as the
/// receiver (first argument) in the [`msg_send!`][`crate::msg_send`] macro.
Expand All @@ -54,6 +52,9 @@ use self::verify::{verify_message_signature, VerificationError};
/// A pointer to the type must be able to be the receiver of an Objective-C
/// message sent with [`objc_msgSend`] or similar.
///
/// The object must also respond to the `retain`, `release` and `autorelease`
/// messages, as that allows it to be used with [`rc::Id`][`Id`].
///
/// Additionally, the type must implement [`RefEncode`] and adhere to the
/// safety requirements therein.
///
Expand All @@ -65,8 +66,6 @@ unsafe impl<T: Message + ?Sized> Message for ManuallyDrop<T> {}

unsafe impl Message for Object {}

unsafe impl Message for Class {}

// TODO: Make this fully private
pub(crate) mod private {
use super::*;
Expand All @@ -84,10 +83,15 @@ pub(crate) mod private {
impl<'a, T: Message + ?Sized> Sealed for &'a mut Id<T, Owned> {}

impl<T: Message + ?Sized, O: Ownership> Sealed for ManuallyDrop<Id<T, O>> {}

impl Sealed for *const Class {}
impl<'a> Sealed for &'a Class {}
}

/// Types that can directly be used as the receiver of Objective-C messages.
///
/// Examples include objects, classes, and blocks.
///
/// This is a sealed trait (for now) that is automatically implemented for
/// pointers to types implementing [`Message`], so that code can be generic
/// over the message receiver.
Expand Down Expand Up @@ -273,6 +277,20 @@ unsafe impl<T: Message + ?Sized, O: Ownership> MessageReceiver for ManuallyDrop<
}
}

unsafe impl MessageReceiver for *const Class {
#[inline]
fn as_raw_receiver(self) -> *mut Object {
self as *mut Class as *mut Object
}
}

unsafe impl<'a> MessageReceiver for &'a Class {
#[inline]
fn as_raw_receiver(self) -> *mut Object {
self as *const Class as *mut Class as *mut Object
}
}

/// Types that may be used as the arguments of an Objective-C message.
///
/// This is implemented for tuples of up to 12 arguments, where each argument
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/fn_ptr_reference_method.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ error[E0277]: the trait bound `extern "C" fn(_, _, _): MethodImplementation` is
for<'r> extern "C" fn(&'r T, objc2::runtime::Sel, A, B, C, D, E) -> R
for<'r> extern "C" fn(&'r T, objc2::runtime::Sel, A, B, C, D, E, F) -> R
for<'r> extern "C" fn(&'r T, objc2::runtime::Sel, A, B, C, D, E, F, G) -> R
and 70 others
and 109 others
note: required by a bound in `ClassBuilder::add_method`
--> $WORKSPACE/objc2/src/declare.rs
|
Expand All @@ -39,7 +39,7 @@ error[E0277]: the trait bound `for<'r> extern "C" fn(_, _, &'r objc2::runtime::O
for<'r> extern "C" fn(&'r T, objc2::runtime::Sel, A, B, C, D, E) -> R
for<'r> extern "C" fn(&'r T, objc2::runtime::Sel, A, B, C, D, E, F) -> R
for<'r> extern "C" fn(&'r T, objc2::runtime::Sel, A, B, C, D, E, F, G) -> R
and 70 others
and 109 others
note: required by a bound in `ClassBuilder::add_method`
--> $WORKSPACE/objc2/src/declare.rs
|
Expand Down
5 changes: 3 additions & 2 deletions tests/ui/msg_send_only_message.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ error[E0277]: the trait bound `{integer}: MessageReceiver` is not satisfied
&'a T
&'a mut Id<T, objc2::rc::Owned>
&'a mut T
&'a objc2::runtime::Class
*const T
*const objc2::runtime::Class
*mut T
ManuallyDrop<Id<T, O>>
NonNull<T>
and 2 others
= note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)