Skip to content

Commit

Permalink
Split CopyOrMutCopy retain semantics in two
Browse files Browse the repository at this point in the history
These should always be handled in the same manner, but splitting them in
two allows for a cleaner implementation of method families.
  • Loading branch information
madsmtm committed Nov 21, 2024
1 parent 602f29e commit ae9e1f5
Show file tree
Hide file tree
Showing 27 changed files with 707 additions and 134 deletions.
13 changes: 8 additions & 5 deletions crates/header-translator/src/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ impl MethodModifiers {
/// This also encodes the "method family" that a method belongs to.
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum MemoryManagement {
IdCopyOrMutCopy,
IdCopy,
IdMutableCopy,
IdNew,
IdInit,
IdOther,
Expand Down Expand Up @@ -175,8 +176,8 @@ impl MemoryManagement {
error!("the `alloc` method-family requires manual handling");
Self::IdOther
}
(false, true, false, false, false) => Self::IdCopyOrMutCopy,
(false, false, true, false, false) => Self::IdCopyOrMutCopy,
(false, true, false, false, false) => Self::IdCopy,
(false, false, true, false, false) => Self::IdMutableCopy,
(false, false, false, true, false) => Self::IdNew,
(false, false, false, false, true) => Self::IdInit,
(false, false, false, false, false) => Self::IdOther,
Expand All @@ -199,7 +200,8 @@ impl MemoryManagement {
modifiers.designated_initializer,
id_type,
) {
(false, false, true, false, false, Self::IdCopyOrMutCopy) => Self::IdCopyOrMutCopy,
(false, false, true, false, false, Self::IdCopy) => Self::IdCopy,
(false, false, true, false, false, Self::IdMutableCopy) => Self::IdMutableCopy,
(false, false, true, false, false, Self::IdNew) => Self::IdNew,
// For the `init` family there's another restriction:
// > must be instance methods
Expand Down Expand Up @@ -689,7 +691,8 @@ impl fmt::Display for Method {
}

let id_mm_name = match &self.memory_management {
MemoryManagement::IdCopyOrMutCopy => Some("CopyOrMutCopy"),
MemoryManagement::IdCopy => Some("Copy"),
MemoryManagement::IdMutableCopy => Some("MutableCopy"),
MemoryManagement::IdNew => Some("New"),
MemoryManagement::IdInit => Some("Init"),
MemoryManagement::IdOther => Some("Other"),
Expand Down
16 changes: 14 additions & 2 deletions crates/objc2/src/__macro_helpers/declare_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::runtime::{AnyProtocol, MethodDescription};
use crate::{ClassType, DeclaredClass, Message, ProtocolType};

use super::declared_ivars::{register_with_ivars, setup_dealloc};
use super::{CopyOrMutCopy, Init, MaybeUnwrap, New, Other};
use super::{Copy, Init, MaybeUnwrap, MutableCopy, New, Other};

/// Helper type for implementing `MethodImplementation` with a receiver of
/// `Allocated<T>`, without exposing that implementation to users.
Expand Down Expand Up @@ -75,7 +75,19 @@ where
}

// Receiver and return type have no correlation
impl<Receiver, Ret> MessageReceiveRetained<Receiver, Ret> for CopyOrMutCopy
impl<Receiver, Ret> MessageReceiveRetained<Receiver, Ret> for Copy
where
Receiver: MessageReceiver,
Ret: MaybeOptionRetained,
{
#[inline]
fn into_return(obj: Ret) -> RetainedReturnValue {
obj.consumed_return()
}
}

// Receiver and return type have no correlation
impl<Receiver, Ret> MessageReceiveRetained<Receiver, Ret> for MutableCopy
where
Receiver: MessageReceiver,
Ret: MaybeOptionRetained,
Expand Down
9 changes: 5 additions & 4 deletions crates/objc2/src/__macro_helpers/method_family.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ pub struct RetainSemantics<const INNER: u8> {}
pub type New = RetainSemantics<1>;
pub type Alloc = RetainSemantics<2>;
pub type Init = RetainSemantics<3>;
pub type CopyOrMutCopy = RetainSemantics<4>;
pub type Other = RetainSemantics<5>;
pub type Copy = RetainSemantics<4>;
pub type MutableCopy = RetainSemantics<5>;
pub type Other = RetainSemantics<6>;

pub const fn retain_semantics(selector: &str) -> u8 {
let selector = selector.as_bytes();
Expand All @@ -40,8 +41,8 @@ pub const fn retain_semantics(selector: &str) -> u8 {
(false, true, false, false, false) => 2,
(false, false, true, false, false) => 3,
(false, false, false, true, false) => 4,
(false, false, false, false, true) => 4,
(false, false, false, false, false) => 5,
(false, false, false, false, true) => 5,
(false, false, false, false, false) => 6,
_ => unreachable!(),
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/objc2/src/__macro_helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub use self::declare_class::{
pub use self::declared_ivars::DeclaredIvarsHelper;
pub use self::image_info::ImageInfo;
pub use self::method_family::{
retain_semantics, Alloc, CopyOrMutCopy, Init, New, Other, RetainSemantics,
retain_semantics, Alloc, Copy, Init, MutableCopy, New, Other, RetainSemantics,
};
pub use self::module_info::ModuleInfo;
pub use self::msg_send::MsgSend;
Expand Down
59 changes: 53 additions & 6 deletions crates/objc2/src/__macro_helpers/msg_send_retained.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::runtime::{AnyClass, AnyObject, Sel};
use crate::{sel, ClassType, DeclaredClass, Message};

use super::declared_ivars::set_finalized;
use super::{Alloc, ConvertArguments, CopyOrMutCopy, Init, MsgSend, New, Other, TupleExtender};
use super::{Alloc, ConvertArguments, Copy, Init, MsgSend, MutableCopy, New, Other, TupleExtender};

pub trait MsgSendRetained<T, U> {
#[track_caller]
Expand Down Expand Up @@ -329,7 +329,7 @@ impl<T: DeclaredClass> MsgSendSuperRetained<PartialInit<T>, Option<Retained<T>>>
}
}

impl<T: MsgSend, U: ?Sized + Message> MsgSendRetained<T, Option<Retained<U>>> for CopyOrMutCopy {
impl<T: MsgSend, U: ?Sized + Message> MsgSendRetained<T, Option<Retained<U>>> for Copy {
#[inline]
unsafe fn send_message_retained<
A: ConvertArguments,
Expand All @@ -348,9 +348,47 @@ impl<T: MsgSend, U: ?Sized + Message> MsgSendRetained<T, Option<Retained<U>>> fo
}
}

impl<T: MsgSend, U: ?Sized + Message> MsgSendSuperRetained<T, Option<Retained<U>>>
for CopyOrMutCopy
{
impl<T: MsgSend, U: ?Sized + Message> MsgSendSuperRetained<T, Option<Retained<U>>> for Copy {
type Inner = T::Inner;

#[inline]
unsafe fn send_super_message_retained<
A: ConvertArguments,
R: MaybeUnwrap<Input = Option<Retained<U>>>,
>(
obj: T,
superclass: &AnyClass,
sel: Sel,
args: A,
) -> R {
// SAFETY: Same as in `send_message_retained`
let obj = unsafe { MsgSend::send_super_message(obj, superclass, sel, args) };
// SAFETY: Same as in `send_message_retained`
let obj = unsafe { Retained::from_raw(obj) };
R::maybe_unwrap::<Self>(obj, ())
}
}

impl<T: MsgSend, U: ?Sized + Message> MsgSendRetained<T, Option<Retained<U>>> for MutableCopy {
#[inline]
unsafe fn send_message_retained<
A: ConvertArguments,
R: MaybeUnwrap<Input = Option<Retained<U>>>,
>(
obj: T,
sel: Sel,
args: A,
) -> R {
// SAFETY: Checked by caller
let obj = unsafe { MsgSend::send_message(obj, sel, args) };
// SAFETY: The selector is `copy` or `mutableCopy`, so this has +1
// retain count
let obj = unsafe { Retained::from_raw(obj) };
R::maybe_unwrap::<Self>(obj, ())
}
}

impl<T: MsgSend, U: ?Sized + Message> MsgSendSuperRetained<T, Option<Retained<U>>> for MutableCopy {
type Inner = T::Inner;

#[inline]
Expand Down Expand Up @@ -525,7 +563,16 @@ impl MsgSendRetainedFailed<'_> for Init {
}
}

impl MsgSendRetainedFailed<'_> for CopyOrMutCopy {
impl MsgSendRetainedFailed<'_> for Copy {
type Args = ();

#[cold]
fn failed(_: Self::Args) -> ! {
panic!("failed copying object")
}
}

impl MsgSendRetainedFailed<'_> for MutableCopy {
type Args = ();

#[cold]
Expand Down
2 changes: 1 addition & 1 deletion crates/objc2/src/macros/__attribute_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ macro_rules! __extract_and_apply_cfg_attributes {
/// 2. The retain semantics, if any was present in the selector for
/// `#[method_id(...)]`.
///
/// One of `New`, `Alloc`, `Init`, `CopyOrMutCopy` and `Other`.
/// One of `New`, `Alloc`, `Init`, `Copy`, `MutableCopy` and `Other`.
/// ($($retain_semantics:ident)?)
///
/// 3. The `optional` attribute, if any.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit ae9e1f5

Please sign in to comment.