Skip to content

Commit

Permalink
Merge pull request #159 from madsmtm/future-proof-traits
Browse files Browse the repository at this point in the history
Future proof `MessageReceiver` and `MethodImplementation` traits
  • Loading branch information
madsmtm authored Jun 11, 2022
2 parents 42b847a + 8c5d3ff commit 195508e
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 34 deletions.
3 changes: 3 additions & 0 deletions objc2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* **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).
* **BREAKING**: Sealed the `MethodImplementation` trait, and made it's `imp`
method privat.

### Fixed
* Properly sealed the `MessageArguments` trait (it already had a hidden
method, so this is not really a breaking change).

### Removed
* **BREAKING**: `ManuallyDrop` no longer implements `Message` directly.
* **BREAKING**: `MessageReceiver::as_raw_receiver` is no longer public.


## 0.3.0-alpha.6 - 2022-01-03
Expand Down
50 changes: 35 additions & 15 deletions objc2/src/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,37 @@ use core::ptr::NonNull;
use std::ffi::CString;

use crate::runtime::{Bool, Class, Imp, Object, Protocol, Sel};
use crate::{ffi, Encode, EncodeArguments, Encoding, Message};
use crate::{ffi, Encode, EncodeArguments, Encoding, Message, RefEncode};

pub(crate) mod private {
pub trait Sealed {}
}

/// Types that can be used as the implementation of an Objective-C method.
pub trait MethodImplementation {
///
/// This is a sealed trait that is implemented for a lot of `extern "C"`
/// function pointer types.
pub trait MethodImplementation: private::Sealed {
/// The callee type of the method.
type Callee: ?Sized;
type Callee: RefEncode + ?Sized;
/// The return type of the method.
type Ret: Encode;
/// The argument types of the method.
type Args: EncodeArguments;

/// Returns self as an [`Imp`] of a method.
fn imp(self) -> Imp;
#[doc(hidden)]
fn __imp(self) -> Imp;
}

macro_rules! method_decl_impl {
(-$s:ident, $r:ident, $f:ty, $($t:ident),*) => (
(-$s:ident, $r:ident, $f:ty, $($t:ident),*) => {
impl<$s, $r, $($t),*> private::Sealed for $f
where
$s: Message + ?Sized,
$r: Encode,
$($t: Encode,)*
{}

impl<$s, $r, $($t),*> MethodImplementation for $f
where
$s: Message + ?Sized,
Expand All @@ -70,12 +84,18 @@ macro_rules! method_decl_impl {
type Ret = $r;
type Args = ($($t,)*);

fn imp(self) -> Imp {
fn __imp(self) -> Imp {
unsafe { mem::transmute(self) }
}
}
);
(@$s:ident, $r:ident, $f:ty, $($t:ident),*) => (
};
(@$s:ident, $r:ident, $f:ty, $($t:ident),*) => {
impl<$r, $($t),*> private::Sealed for $f
where
$r: Encode,
$($t: Encode,)*
{}

impl<$r, $($t),*> MethodImplementation for $f
where
$r: Encode,
Expand All @@ -85,12 +105,12 @@ macro_rules! method_decl_impl {
type Ret = $r;
type Args = ($($t,)*);

fn imp(self) -> Imp {
fn __imp(self) -> Imp {
unsafe { mem::transmute(self) }
}
}
);
($($t:ident),*) => (
};
($($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),*);
Expand All @@ -101,7 +121,7 @@ macro_rules! method_decl_impl {
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),*);
);
};
}

method_decl_impl!();
Expand Down Expand Up @@ -237,7 +257,7 @@ impl ClassBuilder {
ffi::class_addMethod(
self.as_ptr(),
sel.as_ptr() as _,
Some(func.imp()),
Some(func.__imp()),
types.as_ptr(),
)
});
Expand Down Expand Up @@ -275,7 +295,7 @@ impl ClassBuilder {
ffi::class_addMethod(
metaclass,
sel.as_ptr() as _,
Some(func.imp()),
Some(func.__imp()),
types.as_ptr(),
)
});
Expand Down
33 changes: 17 additions & 16 deletions objc2/src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,11 @@ pub(crate) mod private {
///
/// # Safety
///
/// [`Self::as_raw_receiver`] must be implemented correctly.
/// This is a sealed trait, and should not need to be implemented. Open an
/// issue if you know a use-case where this restrition should be lifted!
pub unsafe trait MessageReceiver: private::Sealed + Sized {
/// Get a raw pointer to the receiver of the message.
fn as_raw_receiver(self) -> *mut Object;
#[doc(hidden)]
fn __as_raw_receiver(self) -> *mut Object;

/// Sends a message to self with the given selector and arguments.
///
Expand All @@ -126,7 +127,7 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized {
A: MessageArguments,
R: Encode,
{
let this = self.as_raw_receiver();
let this = self.__as_raw_receiver();
// TODO: Always enable this when `debug_assertions` are on.
#[cfg(feature = "verify_message")]
{
Expand Down Expand Up @@ -173,7 +174,7 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized {
A: MessageArguments,
R: Encode,
{
let this = self.as_raw_receiver();
let this = self.__as_raw_receiver();
#[cfg(feature = "verify_message")]
{
if this.is_null() {
Expand Down Expand Up @@ -210,7 +211,7 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized {
A: EncodeArguments,
R: Encode,
{
let obj = unsafe { &*self.as_raw_receiver() };
let obj = unsafe { &*self.__as_raw_receiver() };
verify_message_signature::<A, R>(obj.class(), sel).map_err(MessageError::from)
}
}
Expand All @@ -220,70 +221,70 @@ pub unsafe trait MessageReceiver: private::Sealed + Sized {

unsafe impl<T: Message + ?Sized> MessageReceiver for *const T {
#[inline]
fn as_raw_receiver(self) -> *mut Object {
fn __as_raw_receiver(self) -> *mut Object {
self as *mut T as *mut Object
}
}

unsafe impl<T: Message + ?Sized> MessageReceiver for *mut T {
#[inline]
fn as_raw_receiver(self) -> *mut Object {
fn __as_raw_receiver(self) -> *mut Object {
self as *mut Object
}
}

unsafe impl<T: Message + ?Sized> MessageReceiver for NonNull<T> {
#[inline]
fn as_raw_receiver(self) -> *mut Object {
fn __as_raw_receiver(self) -> *mut Object {
self.as_ptr() as *mut Object
}
}

unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a T {
#[inline]
fn as_raw_receiver(self) -> *mut Object {
fn __as_raw_receiver(self) -> *mut Object {
self as *const T as *mut T as *mut Object
}
}

unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a mut T {
#[inline]
fn as_raw_receiver(self) -> *mut Object {
fn __as_raw_receiver(self) -> *mut Object {
self as *const T as *mut T as *mut Object
}
}

unsafe impl<'a, T: Message + ?Sized, O: Ownership> MessageReceiver for &'a Id<T, O> {
#[inline]
fn as_raw_receiver(self) -> *mut Object {
fn __as_raw_receiver(self) -> *mut Object {
Id::as_ptr(self) as *mut Object
}
}

unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a mut Id<T, Owned> {
#[inline]
fn as_raw_receiver(self) -> *mut Object {
fn __as_raw_receiver(self) -> *mut Object {
Id::as_mut_ptr(self) as *mut Object
}
}

unsafe impl<T: Message + ?Sized, O: Ownership> MessageReceiver for ManuallyDrop<Id<T, O>> {
#[inline]
fn as_raw_receiver(self) -> *mut Object {
fn __as_raw_receiver(self) -> *mut Object {
Id::consume_as_ptr(self) as *mut Object
}
}

unsafe impl MessageReceiver for *const Class {
#[inline]
fn as_raw_receiver(self) -> *mut Object {
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 {
fn __as_raw_receiver(self) -> *mut Object {
self as *const Class as *mut Class as *mut Object
}
}
Expand Down
6 changes: 3 additions & 3 deletions objc2/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,21 @@ impl crate::message::private::Sealed for ManuallyDrop<CustomObject> {}

unsafe impl MessageReceiver for &CustomObject {
#[inline]
fn as_raw_receiver(self) -> *mut Object {
fn __as_raw_receiver(self) -> *mut Object {
self.obj
}
}

unsafe impl MessageReceiver for &mut CustomObject {
#[inline]
fn as_raw_receiver(self) -> *mut Object {
fn __as_raw_receiver(self) -> *mut Object {
self.obj
}
}

unsafe impl MessageReceiver for ManuallyDrop<CustomObject> {
#[inline]
fn as_raw_receiver(self) -> *mut Object {
fn __as_raw_receiver(self) -> *mut Object {
self.obj
}
}
Expand Down

0 comments on commit 195508e

Please sign in to comment.