Skip to content

Commit 3bb9688

Browse files
authored
Merge pull request #96 from madsmtm/messagereceiver-manuallydrop
Implement `MessageReceiver` and `Message` for `ManuallyDrop`
2 parents 40031dd + 5a24dac commit 3bb9688

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

objc2/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1111
* Added common trait impls on `rc::Owned` and `rc::Shared` (useful in generic
1212
contexts).
1313
* Implement `RefEncode` for `runtime::Protocol`.
14+
* Added `Message` and `MessageReceiver` implementation for `ManuallyDrop<T>`
15+
(where `T` is appropriately bound). This allows patterns like:
16+
```rust
17+
let obj = Id::new(msg_send![class!(MyObject), alloc]);
18+
let obj = ManuallyDrop::new(obj);
19+
// `init` takes ownership and possibly returns a new object.
20+
let obj = Id::new(msg_send![obj, init]);
21+
```
1422

1523
### Changed
1624
* Deprecated `runtime::BOOL`, `runtime::YES` and `runtime::NO`. Use the

objc2/src/message/mod.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use alloc::string::{String, ToString};
22
use core::fmt;
33
use core::mem;
4+
use core::mem::ManuallyDrop;
45
use core::ptr::NonNull;
56
use std::error::Error;
67

@@ -57,13 +58,16 @@ use self::verify::{verify_message_signature, VerificationError};
5758
/// [`objc_msgSend`]: https://developer.apple.com/documentation/objectivec/1456712-objc_msgsend
5859
pub unsafe trait Message: RefEncode {}
5960

61+
// SAFETY: `ManuallyDrop` is `repr(transparent)`.
62+
unsafe impl<T: Message + ?Sized> Message for ManuallyDrop<T> {}
63+
6064
unsafe impl Message for Object {}
6165

6266
unsafe impl Message for Class {}
6367

6468
// TODO: Make this fully private
6569
pub(crate) mod private {
66-
use super::{Id, Message, NonNull, Ownership};
70+
use super::{Id, ManuallyDrop, Message, MessageReceiver, NonNull, Ownership};
6771

6872
pub trait Sealed {}
6973

@@ -74,6 +78,8 @@ pub(crate) mod private {
7478
impl<'a, T: Message + ?Sized> Sealed for &'a mut T {}
7579
impl<T: Message + ?Sized> Sealed for NonNull<T> {}
7680
impl<T: Message, O: Ownership> Sealed for Id<T, O> {}
81+
82+
impl<T: MessageReceiver + ?Sized> Sealed for ManuallyDrop<T> {}
7783
}
7884

7985
/// Types that can directly be used as the receiver of Objective-C messages.
@@ -247,6 +253,13 @@ unsafe impl<T: Message, O: Ownership> MessageReceiver for Id<T, O> {
247253
}
248254
}
249255

256+
unsafe impl<T: MessageReceiver + ?Sized> MessageReceiver for ManuallyDrop<T> {
257+
#[inline]
258+
fn as_raw_receiver(&self) -> *mut Object {
259+
(**self).as_raw_receiver()
260+
}
261+
}
262+
250263
/// Types that may be used as the arguments of an Objective-C message.
251264
///
252265
/// This is implemented for tuples of up to 12 arguments, where each argument
@@ -419,6 +432,21 @@ mod tests {
419432
}
420433
}
421434

435+
#[test]
436+
fn test_send_message_manuallydrop() {
437+
let obj = test_utils::custom_object();
438+
let obj = ManuallyDrop::new(obj);
439+
let result: u32 = unsafe {
440+
let _: () = msg_send![obj, setFoo: 4u32];
441+
msg_send![obj, foo]
442+
};
443+
assert_eq!(result, 4);
444+
445+
let obj: *const ManuallyDrop<Object> = (&**obj as *const Object).cast();
446+
let result: u32 = unsafe { msg_send![obj, foo] };
447+
assert_eq!(result, 4);
448+
}
449+
422450
#[test]
423451
fn test_verify_message() {
424452
let obj = test_utils::custom_object();

0 commit comments

Comments
 (0)