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 20, 2025
1 parent e09a2c7 commit 96cdc11
Show file tree
Hide file tree
Showing 136 changed files with 3,004 additions and 2,998 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
3 changes: 3 additions & 0 deletions crates/objc2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ objc2-core-foundation = { path = "../../framework-crates/objc2-core-foundation",
objc2-foundation = { path = "../../framework-crates/objc2-foundation", default-features = false, features = [
"std",
"NSArray",
"NSBundle",
"NSDate",
"NSDictionary",
"NSEnumerator",
Expand All @@ -141,6 +142,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
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
25 changes: 13 additions & 12 deletions crates/objc2/src/__macro_helpers/defined_ivars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ mod tests {
use super::*;
use crate::rc::{Allocated, PartialInit, RcTestObject, Retained, ThreadTestData};
use crate::runtime::NSObject;
use crate::{define_class, msg_send, msg_send_id, AllocAnyThread, Message};
use crate::{define_class, msg_send, AllocAnyThread, Message};

/// Initialize superclasses, but not own class.
unsafe fn init_only_superclasses<T: DefinedClass>(obj: Allocated<T>) -> Retained<T>
Expand All @@ -445,7 +445,8 @@ mod tests {
unsafe { Retained::from_raw(msg_send![super(Allocated::into_ptr(obj)), init]) }.unwrap()
}

/// Initialize, but fail to finalize (which is only done by `msg_send_id!`).
/// Initialize, but fail to finalize (which is done internally by
/// `msg_send!` when returning `Retained`).
unsafe fn init_no_finalize<T: DefinedClass>(obj: Allocated<T>) -> Retained<T>
where
T::Super: ClassType,
Expand All @@ -457,7 +458,7 @@ mod tests {

/// Initialize properly.
unsafe fn init<T: DefinedClass>(obj: Allocated<T>) -> Retained<T> {
unsafe { msg_send_id![obj, init] }
unsafe { msg_send![obj, init] }
}

#[test]
Expand Down Expand Up @@ -505,7 +506,7 @@ mod tests {
unsafe impl ImplsDrop {
#[method_id(init)]
fn init(this: Allocated<Self>) -> Option<Retained<Self>> {
unsafe { msg_send_id![super(this.set_ivars(())), init] }
unsafe { msg_send![super(this.set_ivars(())), init] }
}
}
);
Expand Down Expand Up @@ -539,7 +540,7 @@ mod tests {
unsafe impl IvarsImplDrop {
#[method_id(init)]
fn init(this: Allocated<Self>) -> Option<Retained<Self>> {
unsafe { msg_send_id![super(this.set_ivars(IvarThatImplsDrop)), init] }
unsafe { msg_send![super(this.set_ivars(IvarThatImplsDrop)), init] }
}
}
);
Expand Down Expand Up @@ -567,7 +568,7 @@ mod tests {
unsafe impl BothIvarsAndTypeImplsDrop {
#[method_id(init)]
fn init(this: Allocated<Self>) -> Option<Retained<Self>> {
unsafe { msg_send_id![super(this.set_ivars(IvarThatImplsDrop)), init] }
unsafe { msg_send![super(this.set_ivars(IvarThatImplsDrop)), init] }
}
}
);
Expand Down Expand Up @@ -637,7 +638,7 @@ mod tests {
unsafe impl IvarZst {
#[method_id(init)]
fn init(this: Allocated<Self>) -> Option<Retained<Self>> {
unsafe { msg_send_id![super(this.set_ivars(Cell::new(Ivar))), init] }
unsafe { msg_send![super(this.set_ivars(Cell::new(Ivar))), init] }
}
}
);
Expand Down Expand Up @@ -701,7 +702,7 @@ mod tests {
#[method_id(init)]
fn init(this: Allocated<Self>) -> Option<Retained<Self>> {
let this = this.set_ivars(Cell::new(Some(RcTestObject::new())));
unsafe { msg_send_id![super(this), init] }
unsafe { msg_send![super(this), init] }
}
}
);
Expand Down Expand Up @@ -764,7 +765,7 @@ mod tests {
int: Cell::new(42),
obj: Cell::new(RcTestObject::new()),
});
unsafe { msg_send_id![super(this), init] }
unsafe { msg_send![super(this), init] }
}
}
);
Expand Down Expand Up @@ -846,7 +847,7 @@ mod tests {
}

let obj = DropPanics::alloc().set_ivars(());
let obj: Retained<DropPanics> = unsafe { msg_send_id![super(obj), init] };
let obj: Retained<DropPanics> = unsafe { msg_send![super(obj), init] };
drop(obj);
}

Expand All @@ -870,7 +871,7 @@ mod tests {
);

let obj = IvarDropPanics::alloc().set_ivars(DropPanics);
let obj: Retained<IvarDropPanics> = unsafe { msg_send_id![super(obj), init] };
let obj: Retained<IvarDropPanics> = unsafe { msg_send![super(obj), init] };
drop(obj);
}

Expand Down Expand Up @@ -907,7 +908,7 @@ mod tests {
}

let obj = DropRetainsAndLeaksSelf::alloc().set_ivars(());
let obj: Retained<DropRetainsAndLeaksSelf> = unsafe { msg_send_id![super(obj), init] };
let obj: Retained<DropRetainsAndLeaksSelf> = unsafe { msg_send![super(obj), init] };
drop(obj);

// Suddenly, the object is alive again!
Expand Down
14 changes: 13 additions & 1 deletion crates/objc2/src/__macro_helpers/method_family.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/// The slight difference here is:
/// - The method may be annotated with the `objc_method_family` attribute,
/// which would cause it to be in a different family. That this is not the
/// case is part of the `unsafe` contract of `msg_send_id!`.
/// case is part of the `unsafe` contract of `msg_send!`.
/// - The method may not obey the added restrictions of the method family.
/// The added restrictions are:
/// - `new`, `alloc`, `copy` and `mutableCopy`: The method must return a
Expand Down Expand Up @@ -39,6 +39,18 @@ pub type NoneFamily = MethodFamily<6>;
/// Used for a fast-path optimization using `objc_alloc`.
pub type AllocSelector = MethodFamily<7>;

// These are used to avoid trying to do retain-semantics for these special
// selectors that would otherwise fall under `NoneFamily`.

/// The `retain` selector itself.
pub type RetainSelector = MethodFamily<8>;
/// The `release` selector itself.
pub type ReleaseSelector = MethodFamily<9>;
/// The `autorelease` selector itself.
pub type AutoreleaseSelector = MethodFamily<10>;
/// The `dealloc` selector itself.
pub type DeallocSelector = MethodFamily<11>;

/// Helper module where `#[unsafe(method_family = $family:ident)]` will import
/// its value from.
#[allow(non_camel_case_types)]
Expand Down
13 changes: 8 additions & 5 deletions crates/objc2/src/__macro_helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ pub(crate) mod defined_ivars;
mod image_info;
mod method_family;
mod module_info;
mod msg_send;
mod msg_send_retained;
mod null_error;
mod os_version;
mod retain_semantics;
mod sync_unsafe_cell;
mod writeback;

Expand All @@ -41,13 +41,16 @@ pub use self::define_class::{
pub use self::defined_ivars::DefinedIvarsHelper;
pub use self::image_info::ImageInfo;
pub use self::method_family::{
method_family, method_family_import, AllocFamily, AllocSelector, CopyFamily, InitFamily,
MethodFamily, MutableCopyFamily, NewFamily, NoneFamily,
method_family, method_family_import, AllocFamily, AllocSelector, AutoreleaseSelector,
CopyFamily, DeallocSelector, InitFamily, MethodFamily, MutableCopyFamily, NewFamily,
NoneFamily, ReleaseSelector, RetainSelector,
};
pub use self::module_info::ModuleInfo;
pub use self::msg_send::MsgSend;
pub use self::msg_send_retained::{MaybeUnwrap, MsgSendRetained, MsgSendSuperRetained};
pub use self::msg_send_retained::{MsgSend, MsgSendError, MsgSendSuper, MsgSendSuperError};
pub use self::os_version::{is_available, AvailableVersion, OSVersion};
pub use self::retain_semantics::{
KindDefined, KindSendMessage, KindSendMessageSuper, RetainSemantics,
};
pub use self::sync_unsafe_cell::SyncUnsafeCell;

/// Disallow using this passed in value in const and statics for forwards
Expand Down
Loading

0 comments on commit 96cdc11

Please sign in to comment.