Skip to content

Commit

Permalink
Merge msg_send! and msg_send_id!
Browse files Browse the repository at this point in the history
Merge all message sending functionality into one shared implementation,
to make it easier for newcomers to use (instead of having to remember
the difference between `#[method(...)]` and `#[method_id(...)]`).

This also deprecates `msg_send_id!` and `#[method_id(...)]`, which is
a bit step of #617.

Fixes #457.
  • Loading branch information
madsmtm committed Jan 21, 2025
1 parent aa6e383 commit d70c602
Show file tree
Hide file tree
Showing 141 changed files with 3,494 additions and 3,383 deletions.
37 changes: 13 additions & 24 deletions crates/header-translator/src/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,32 +767,21 @@ impl fmt::Display for Method {
writeln!(f, " #[optional]")?;
}

let method_kind = if self.memory_management == MemoryManagement::Normal {
"method"
} else {
"method_id"
};
let error_trailing = if self.is_error { "_" } else { "" };
writeln!(
f,
" #[{}({}{})]",
method_kind, self.selector, error_trailing
)?;

let id_mm_name = match &self.memory_management {
// MemoryManagement::IdAlloc => Some("alloc"), // Unsupported
MemoryManagement::IdCopy => Some("copy"),
MemoryManagement::IdMutableCopy => Some("mutableCopy"),
MemoryManagement::IdNew => Some("new"),
MemoryManagement::IdInit => Some("init"),
MemoryManagement::IdOther => Some("none"),
MemoryManagement::Normal => None,
};
if let Some(id_mm_name) = id_mm_name {
// TODO: Be explicit about when we emit this for better
// compile-times, and when we do it for soundness.
writeln!(f, " #[unsafe(method_family = {id_mm_name})]")?;
writeln!(f, " #[method({}{})]", self.selector, error_trailing)?;

let method_family = match &self.memory_management {
// MemoryManagement::IdAlloc => "alloc", // Unsupported
MemoryManagement::IdCopy => "copy",
MemoryManagement::IdMutableCopy => "mutableCopy",
MemoryManagement::IdNew => "new",
MemoryManagement::IdInit => "init",
MemoryManagement::IdOther => "none",
MemoryManagement::Normal => "none",
};
// TODO: Be explicit about when we emit this for better
// compile-times, and when we do it for soundness.
writeln!(f, " #[unsafe(method_family = {method_family})]")?;

//
// Signature
Expand Down
6 changes: 3 additions & 3 deletions crates/header-translator/src/rust_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2404,7 +2404,7 @@ impl Ty {

// As in `parse_property_return`, the nullability is not guaranteed by
// the method, and can also fail in OOM situations, but that is
// handled by `#[method_id(...)]`
// handled by `#[method(...)]`
if default_nonnull {
match &mut ty {
Self::Pointer { nullability, .. } => {
Expand Down Expand Up @@ -2512,8 +2512,8 @@ impl Ty {
// can also fail in OOM situations, so we must still perform an unwrap
// to be sure (Swift also uses forced unwrapping here).
//
// This unwrap is done by `#[method_id(...)]` when we specify the
// return type as `Retained`.
// This unwrap is done by `#[method(...)]` when we specify the return
// type as `Retained`.
if is_copy {
match &mut ty {
Self::Pointer { nullability, .. } => {
Expand Down
3 changes: 3 additions & 0 deletions crates/objc2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
`AnyObject::downcast_ref` method instead.
* Deprecated `Retained::cast`, this has been renamed to `Retained::cast_unchecked`.
* Renamed `DeclaredClass` to `DefinedClass`.
* Merged `msg_send!` and `msg_send_id!`. The latter is now deprecated.
* Merged `#[method(...)]` and `#[method_id(...)]` in `extern_methods!` and
`extern_protocol!`. The latter is now deprecated.

### Removed
* **BREAKING**: Removed the `ffi::SEL` and `ffi::objc_selector` types. Use
Expand Down
2 changes: 2 additions & 0 deletions crates/objc2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ objc2-foundation = { path = "../../framework-crates/objc2-foundation", default-f
"NSObject",
"NSRunLoop",
"NSString",
"NSURL",
"NSValue",
] }
libc = "0.2.158"

Expand Down
5 changes: 2 additions & 3 deletions crates/objc2/examples/class_with_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ use std::cell::Cell;
use std::marker::PhantomData;
use std::sync::Once;

use objc2::msg_send_id;
use objc2::rc::Retained;
use objc2::runtime::{AnyClass, AnyObject, ClassBuilder, NSObject};
use objc2::{ClassType, Encoding, Message, RefEncode};
use objc2::{msg_send, ClassType, Encoding, Message, RefEncode};

/// The type of the instance variable that we want to store
type Ivar<'a> = &'a Cell<u8>;
Expand Down Expand Up @@ -49,7 +48,7 @@ impl<'a> MyObject<'a> {

fn new(number: &'a mut u8) -> Retained<Self> {
// SAFETY: The instance variable is initialized below.
let this: Retained<Self> = unsafe { msg_send_id![Self::class(), new] };
let this: Retained<Self> = unsafe { msg_send![Self::class(), new] };

// It is generally very hard to use `mut` in Objective-C, so let's use
// interior mutability instead.
Expand Down
4 changes: 2 additions & 2 deletions crates/objc2/src/__macro_helpers/common_selectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ mod tests {
use crate::rc::Retained;
use crate::runtime::ClassBuilder;
use crate::runtime::NSObject;
use crate::{msg_send_id, ClassType};
use crate::{msg_send, ClassType};

use super::*;

Expand All @@ -103,7 +103,7 @@ mod tests {

let cls = builder.register();

let obj: Retained<NSObject> = unsafe { msg_send_id![cls, new] };
let obj: Retained<NSObject> = unsafe { msg_send![cls, new] };
drop(obj);
let has_run_destruct = HAS_RUN.load(Ordering::Relaxed);

Expand Down
82 changes: 54 additions & 28 deletions crates/objc2/src/__macro_helpers/convert.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::encode::{EncodeArgument, EncodeArguments, EncodeReturn};
use crate::rc::Retained;
use crate::runtime::Bool;
use crate::rc::{Allocated, Retained};
use crate::runtime::{AnyObject, Bool, Sel};
use crate::Message;

mod argument_private {
Expand Down Expand Up @@ -88,48 +88,64 @@ mod return_private {
}

/// Same as [`ConvertArgument`], but for return types.
pub trait ConvertReturn: return_private::Sealed {
/// The inner type that this can be converted to and from.
#[doc(hidden)]
type __Inner: EncodeReturn;

#[doc(hidden)]
fn __into_defined_return(self) -> Self::__Inner;

#[doc(hidden)]
fn __from_return(inner: Self::__Inner) -> Self;
///
/// See `RetainSemantics` for more details.
pub trait ConvertReturn<MethodFamily>: return_private::Sealed {
type Inner: EncodeReturn;

#[track_caller]
unsafe fn convert_message_return(
inner: Self::Inner,
receiver_ptr: *mut AnyObject,
sel: Sel,
) -> Self;

fn convert_defined_return(self) -> Self::Inner;
}

impl<T: EncodeReturn> return_private::Sealed for T {}
impl<T: EncodeReturn> ConvertReturn for T {
type __Inner = Self;
impl<T: EncodeReturn, MethodFamily> ConvertReturn<MethodFamily> for T {
type Inner = Self;

#[inline]
fn __into_defined_return(self) -> Self::__Inner {
self
unsafe fn convert_message_return(
inner: Self::Inner,
_receiver_ptr: *mut AnyObject,
_sel: Sel,
) -> Self {
inner
}

#[inline]
fn __from_return(inner: Self::__Inner) -> Self {
inner
fn convert_defined_return(self) -> Self::Inner {
self
}
}

impl return_private::Sealed for bool {}
impl ConvertReturn for bool {
type __Inner = Bool;
impl<MethodFamily> ConvertReturn<MethodFamily> for bool {
type Inner = Bool;

#[inline]
fn __into_defined_return(self) -> Self::__Inner {
Bool::new(self)
unsafe fn convert_message_return(
inner: Self::Inner,
_receiver_ptr: *mut AnyObject,
_sel: Sel,
) -> Self {
inner.as_bool()
}

#[inline]
fn __from_return(inner: Self::__Inner) -> Self {
inner.as_bool()
fn convert_defined_return(self) -> Self::Inner {
Bool::new(self)
}
}

// Implemented in retain_semantics.rs
impl<T: ?Sized + Message> return_private::Sealed for Retained<T> {}
impl<T: ?Sized + Message> return_private::Sealed for Option<Retained<T>> {}
impl<T: ?Sized + Message> return_private::Sealed for Allocated<T> {}

pub trait ConvertArguments {
#[doc(hidden)]
type __Inner: EncodeArguments;
Expand Down Expand Up @@ -287,6 +303,9 @@ mod tests {
use super::*;

use core::any::TypeId;
use core::ptr;

use crate::sel;

#[test]
fn convert_normally_noop() {
Expand All @@ -310,15 +329,22 @@ mod tests {

#[test]
fn convert_bool() {
let receiver_ptr = ptr::null_mut::<AnyObject>();
let sel = sel!(foo);

assert!(!<bool as ConvertArgument>::__from_defined_param(Bool::NO));
assert!(<bool as ConvertArgument>::__from_defined_param(Bool::YES));
assert!(!<bool as ConvertReturn>::__from_return(Bool::NO));
assert!(<bool as ConvertReturn>::__from_return(Bool::YES));
assert!(!unsafe {
<bool as ConvertReturn<()>>::convert_message_return(Bool::NO, receiver_ptr, sel)
});
assert!(unsafe {
<bool as ConvertReturn<()>>::convert_message_return(Bool::YES, receiver_ptr, sel)
});

assert!(!unsafe { ConvertArgument::__into_argument(false).0 }.as_bool());
assert!(unsafe { ConvertArgument::__into_argument(true).0 }.as_bool());
assert!(!ConvertReturn::__into_defined_return(false).as_bool());
assert!(ConvertReturn::__into_defined_return(true).as_bool());
assert!(!ConvertReturn::<()>::convert_defined_return(false).as_bool());
assert!(ConvertReturn::<()>::convert_defined_return(true).as_bool());

#[cfg(all(target_vendor = "apple", target_os = "macos", target_arch = "x86_64"))]
assert_eq!(
Expand Down
12 changes: 9 additions & 3 deletions crates/objc2/src/__macro_helpers/define_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::runtime::{AnyProtocol, MethodDescription};
use crate::{AllocAnyThread, ClassType, DefinedClass, Message, ProtocolType};

use super::defined_ivars::{register_with_ivars, setup_dealloc};
use super::{CopyFamily, InitFamily, MaybeUnwrap, MutableCopyFamily, NewFamily, NoneFamily};
use super::{CopyFamily, InitFamily, MutableCopyFamily, NewFamily, NoneFamily};

/// Helper for determining auto traits of defined classes.
///
Expand Down Expand Up @@ -97,7 +97,7 @@ where
impl<Ret, T> MessageReceiveRetained<Allocated<T>, Ret> for InitFamily
where
T: Message,
Ret: MaybeOptionRetained<Input = Option<Retained<T>>>,
Ret: MaybeOptionRetained<Inner = T>,
{
#[inline]
fn into_return(obj: Ret) -> RetainedReturnValue {
Expand Down Expand Up @@ -144,12 +144,16 @@ where
/// Helper trait for specifying an `Retained<T>` or an `Option<Retained<T>>`.
///
/// (Both of those are valid return types from define_class! `#[method_id]`).
pub trait MaybeOptionRetained: MaybeUnwrap {
pub trait MaybeOptionRetained {
type Inner;

fn consumed_return(self) -> RetainedReturnValue;
fn autorelease_return(self) -> RetainedReturnValue;
}

impl<T: Message> MaybeOptionRetained for Retained<T> {
type Inner = T;

#[inline]
fn consumed_return(self) -> RetainedReturnValue {
let ptr: *mut T = Retained::into_raw(self);
Expand All @@ -164,6 +168,8 @@ impl<T: Message> MaybeOptionRetained for Retained<T> {
}

impl<T: Message> MaybeOptionRetained for Option<Retained<T>> {
type Inner = T;

#[inline]
fn consumed_return(self) -> RetainedReturnValue {
let ptr: *mut T = Retained::consume_as_ptr_option(self);
Expand Down
Loading

0 comments on commit d70c602

Please sign in to comment.