Skip to content

Commit

Permalink
Consume ManuallyDrop<Id<T, O>> in msg_send!
Browse files Browse the repository at this point in the history
If you do not want to consume it, the possibility of doing `msg_send![&*obj]` exists, but most of the time that is indeed what you want (I mean, why else would you wrap it in `ManuallyDrop`?)
  • Loading branch information
madsmtm committed Jun 6, 2022
1 parent d9a328e commit 7a94811
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 36 deletions.
28 changes: 7 additions & 21 deletions objc2/src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ pub(crate) mod private {
impl<'a, T: Message + ?Sized, O: Ownership> Sealed for &'a Id<T, O> {}
impl<'a, T: Message + ?Sized> Sealed for &'a mut Id<T, Owned> {}

impl<'a, T: Message + ?Sized, O: Ownership> Sealed for &'a ManuallyDrop<Id<T, O>> {}
impl<'a, T: Message + ?Sized> Sealed for &'a mut ManuallyDrop<Id<T, Owned>> {}
impl<T: Message + ?Sized, O: Ownership> Sealed for ManuallyDrop<Id<T, O>> {}
}

/// Types that can directly be used as the receiver of Objective-C messages.
Expand Down Expand Up @@ -267,17 +266,10 @@ unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a mut Id<T, Owned> {
}
}

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

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

Expand Down Expand Up @@ -481,17 +473,11 @@ mod tests {

#[test]
fn test_send_message_manuallydrop() {
let obj = test_utils::custom_object();
let mut obj = ManuallyDrop::new(obj);
let result: u32 = unsafe {
let _: () = msg_send![&mut obj, setFoo: 4u32];
msg_send![&obj, foo]
let obj = ManuallyDrop::new(test_utils::custom_object());
unsafe {
let _: () = msg_send![obj, release];
};
assert_eq!(result, 4);

let obj: *const ManuallyDrop<Object> = obj.as_ptr().cast();
let result: u32 = unsafe { msg_send![obj, foo] };
assert_eq!(result, 4);
// `obj` is consumed, can't use here
}

#[test]
Expand Down
5 changes: 5 additions & 0 deletions objc2/src/rc/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,11 @@ impl<T: Message + ?Sized, O: Ownership> Id<T, O> {
pub fn as_ptr(this: &Id<T, O>) -> *const T {
this.ptr.as_ptr()
}

#[inline]
pub(crate) fn consume_as_ptr(this: ManuallyDrop<Self>) -> *mut T {
this.ptr.as_ptr()
}
}

impl<T: Message + ?Sized> Id<T, Owned> {
Expand Down
29 changes: 16 additions & 13 deletions objc2/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,34 +23,26 @@ impl CustomObject {
// TODO: Remove the need for this hack
impl crate::message::private::Sealed for &CustomObject {}
impl crate::message::private::Sealed for &mut CustomObject {}
impl crate::message::private::Sealed for &ManuallyDrop<CustomObject> {}
impl crate::message::private::Sealed for &mut ManuallyDrop<CustomObject> {}
impl crate::message::private::Sealed for ManuallyDrop<CustomObject> {}

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

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

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

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

Expand Down Expand Up @@ -106,6 +98,14 @@ pub(crate) fn custom_class() -> &'static Class {
builder.add_protocol(proto);
builder.add_ivar::<u32>("_foo");

unsafe extern "C" fn custom_obj_release(
this: *mut Object,
_cmd: Sel,
) {
// Drop the value
let _ = CustomObject { obj: this };
}

extern "C" fn custom_obj_set_foo(this: &mut Object, _cmd: Sel, foo: u32) {
unsafe {
this.set_ivar::<u32>("_foo", foo);
Expand Down Expand Up @@ -145,6 +145,9 @@ pub(crate) fn custom_class() -> &'static Class {
}

unsafe {
let release: unsafe extern "C" fn(*mut Object, Sel) = custom_obj_release;
builder.add_method(sel!(release), release);

let set_foo: extern "C" fn(&mut Object, Sel, u32) = custom_obj_set_foo;
builder.add_method(sel!(setFoo:), set_foo);
let get_foo: extern "C" fn(&Object, Sel) -> u32 = custom_obj_get_foo;
Expand Down
3 changes: 1 addition & 2 deletions tests/ui/msg_send_only_message.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ error[E0277]: the trait bound `{integer}: MessageReceiver` is not satisfied
|
= help: the following other types implement trait `MessageReceiver`:
&'a Id<T, O>
&'a ManuallyDrop<Id<T, O>>
&'a T
&'a mut Id<T, objc2::rc::Owned>
&'a mut ManuallyDrop<Id<T, objc2::rc::Owned>>
&'a mut T
*const T
*mut T
ManuallyDrop<Id<T, O>>
NonNull<T>
= note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)

0 comments on commit 7a94811

Please sign in to comment.