Skip to content

Commit f0591af

Browse files
authored
Merge pull request #514 from madsmtm/msg-send-refactor
Refactor message sending
2 parents 5e705a7 + 0a6df20 commit f0591af

File tree

96 files changed

+3566
-3132
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+3566
-3132
lines changed

LAYERED_SAFETY.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ Doing the Rust equivalent of Objective-C's `NSUInteger hash_code = [obj hash];`.
5252

5353
```rust
5454
let obj: *const c_void = ...;
55-
let sel = unsafe { sel_registerName(b"hash\0".as_ptr() as *const c_char) };
56-
let fnptr = unsafe {
55+
let sel = unsafe { ffi::sel_registerName(b"hash\0".as_ptr() as *const c_char) };
56+
let msg_send_fn = unsafe {
5757
mem::transmute::<
58-
extern "C" fn(*const c_void, SEL) -> NSUInteger,
59-
extern "C" fn(),
60-
>(objc_msgSend)
58+
unsafe extern "C" fn(),
59+
unsafe extern "C" fn(*const c_void, SEL) -> NSUInteger,
60+
>(ffi::objc_msgSend)
6161
};
62-
let hash_code = unsafe { fnptr(obj, sel) };
62+
let hash_code = unsafe { msg_send_fn(obj, sel) };
6363
```
6464

6565

@@ -68,8 +68,7 @@ let hash_code = unsafe { fnptr(obj, sel) };
6868
We can improve on this using [`MessageReceiver::send_message`], which
6969
abstracts away the calling convention details, as well as adding an `Encode`
7070
bound on all the involved types. This ensures that we don't accidentally try
71-
to pass e.g. a `Vec<T>`, which does not have a stable memory layout. It also
72-
handles details surrounding Objective-C's `BOOL` type.
71+
to pass e.g. a `Vec<T>`, which does not have a stable memory layout.
7372

7473
Additionally, when `debug_assertions` are enabled, the types involved in the
7574
message send are compared to the types exposed in the Objective-C runtime.
@@ -97,7 +96,8 @@ let hash_code: NSUInteger = unsafe {
9796

9897
Introducing macros: [`msg_send!`] can abstract away the tediousness of writing
9998
the selector expression, as well as ensuring that the number of arguments to
100-
the method is correct.
99+
the method is correct. It also handles details surrounding Objective-C's
100+
`BOOL` type.
101101

102102
[`msg_send!`]: https://docs.rs/objc2/0.3.0-beta.4/objc2/macro.msg_send.html
103103

crates/icrate/tests/array.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#![cfg(feature = "Foundation_NSArray")]
22
#![cfg(feature = "Foundation_NSNumber")]
3+
use core::ptr;
4+
35
use icrate::Foundation::{NSArray, NSNumber, NSObject};
46
use objc2::mutability::IsRetainable;
57
use objc2::rc::{Id, __RcTestObject, __ThreadTestData};
6-
use objc2::runtime::ProtocolObject;
8+
use objc2::runtime::{AnyObject, ProtocolObject};
79
use objc2::{extern_protocol, ProtocolType};
810

911
fn sample_array(len: usize) -> Id<NSArray<NSObject>> {
@@ -283,3 +285,15 @@ fn test_trait_retainable() {
283285
let _ = NSArray::from_id_slice(&[obj.clone(), obj.clone()]);
284286
let _ = NSArray::from_vec(vec![obj.clone(), obj.clone()]);
285287
}
288+
289+
#[test]
290+
fn test_access_anyobject() {
291+
let obj: Id<AnyObject> = Id::into_super(NSObject::new());
292+
let array = NSArray::from_id_slice(&[obj.clone(), obj.clone()]);
293+
assert!(ptr::eq(&array[0], &*obj));
294+
assert!(ptr::eq(array.get(0).unwrap(), &*obj));
295+
assert!(ptr::eq(&*array.get_retained(0).unwrap(), &*obj));
296+
for _ in array.iter() {}
297+
for _ in array.iter_retained() {}
298+
for _ in array {}
299+
}

crates/objc2/CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1010
* Added the following traits to the `mutability` module (see the documentation
1111
for motivation and usage info):
1212
- `HasStableHash`.
13+
- `IsAllowedMutable`.
1314
- `IsMainThreadOnly`.
1415
- `CounterpartOrSelf`.
1516
* Added new `encode` traits `EncodeReturn`, `EncodeArgument` and
@@ -25,6 +26,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
2526
This effectively means you can now `copy` a `ProtocolObject<dyn NSCopying>`.
2627
* **BREAKING**: Allow implementing `DefaultId` for any type, not just those
2728
who are `IsAllocableAnyThread`.
29+
* **BREAKING**: Moved the `MethodImplementation` trait from the `declare`
30+
module to the `runtime` module.
31+
* **BREAKING**: Moved the `MessageReceiver` trait to the `runtime` module.
32+
* **BREAKING**: Make the `MessageReceiver` trait no longer implemented for
33+
references to `Id`. Dereference the `Id` yourself.
34+
35+
Note: Passing `&Id` in `msg_send!` is still supported.
36+
* **BREAKING**: `MessageReceiver::send_message` and
37+
`MessageReceiver::send_super_message` now take `EncodeArguments` and return
38+
`EncodeReturn`, instead of internal traits.
39+
40+
This is done to make `MessageReceiver` more straightforward to understand,
41+
although it now also has slightly less functionality than `msg_send!`.
42+
43+
In particular automatic conversion of `bool` is not supported in
44+
`MessageReceiver`.
45+
* Relaxed the requirements for receivers in `MethodImplementation`; now,
46+
anything that implements `MessageReceiver` can be used as the receiver of
47+
a method.
48+
* **BREAKING**: Renamed the associated types `Ret` and `Args` on
49+
`MethodImplementation` to `Return` and `Arguments`.
2850

2951
### Deprecated
3052
* Soft deprecated using `msg_send!` without a comma between arguments (i.e.
@@ -52,10 +74,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5274

5375
### Fixed
5476
* Fixed the name of the protocol that `NSObjectProtocol` references.
77+
* Allow cloning `Id<AnyObject>`.
78+
* **BREAKING**: Restrict message sending to `&mut` references to things that
79+
implement `IsAllowedMutable`.
5580

5681
### Removed
5782
* **BREAKING**: Removed `ProtocolType` implementation for `NSObject`.
5883
Use the more precise `NSObjectProtocol` trait instead!
84+
* **BREAKING**: Removed the `MessageArguments` trait.
5985

6086

6187
## 0.4.1 - 2023-07-31

crates/objc2/src/__macro_helpers/convert.rs

Lines changed: 163 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::encode::{EncodeArgument, EncodeReturn};
1+
use crate::encode::{EncodeArgument, EncodeArguments, EncodeReturn};
22
use crate::rc::Id;
33
use crate::runtime::Bool;
44
use crate::Message;
@@ -31,6 +31,7 @@ pub trait ConvertArgument: argument_private::Sealed {
3131
fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage);
3232

3333
#[doc(hidden)]
34+
#[inline]
3435
unsafe fn __process_after_message_send(_stored: Self::__StoredBeforeMessage) {}
3536
}
3637

@@ -121,6 +122,167 @@ impl ConvertReturn for bool {
121122
}
122123
}
123124

125+
pub trait ConvertArguments {
126+
#[doc(hidden)]
127+
type __Inner: EncodeArguments;
128+
129+
#[doc(hidden)]
130+
type __StoredBeforeMessage: Sized;
131+
132+
#[doc(hidden)]
133+
fn __into_arguments(self) -> (Self::__Inner, Self::__StoredBeforeMessage);
134+
135+
#[doc(hidden)]
136+
unsafe fn __process_after_message_send(_stored: Self::__StoredBeforeMessage);
137+
}
138+
139+
pub trait TupleExtender<T> {
140+
#[doc(hidden)]
141+
type PlusOneArgument;
142+
#[doc(hidden)]
143+
fn add_argument(self, arg: T) -> Self::PlusOneArgument;
144+
}
145+
146+
macro_rules! args_impl {
147+
($($a:ident: $t:ident),*) => (
148+
impl<$($t: ConvertArgument),*> ConvertArguments for ($($t,)*) {
149+
type __Inner = ($($t::__Inner,)*);
150+
151+
type __StoredBeforeMessage = ($($t::__StoredBeforeMessage,)*);
152+
153+
#[inline]
154+
fn __into_arguments(self) -> (Self::__Inner, Self::__StoredBeforeMessage) {
155+
let ($($a,)*) = self;
156+
$(let $a = ConvertArgument::__into_argument($a);)*
157+
158+
(($($a.0,)*), ($($a.1,)*))
159+
}
160+
161+
#[inline]
162+
unsafe fn __process_after_message_send(($($a,)*): Self::__StoredBeforeMessage) {
163+
$(
164+
unsafe { <$t as ConvertArgument>::__process_after_message_send($a) };
165+
)*
166+
}
167+
}
168+
169+
impl<$($t,)* T> TupleExtender<T> for ($($t,)*) {
170+
type PlusOneArgument = ($($t,)* T,);
171+
172+
#[inline]
173+
fn add_argument(self, arg: T) -> Self::PlusOneArgument {
174+
let ($($a,)*) = self;
175+
($($a,)* arg,)
176+
}
177+
}
178+
);
179+
}
180+
181+
args_impl!();
182+
args_impl!(a: A);
183+
args_impl!(a: A, b: B);
184+
args_impl!(a: A, b: B, c: C);
185+
args_impl!(a: A, b: B, c: C, d: D);
186+
args_impl!(a: A, b: B, c: C, d: D, e: E);
187+
args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
188+
args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
189+
args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
190+
args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
191+
args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
192+
args_impl!(
193+
a: A,
194+
b: B,
195+
c: C,
196+
d: D,
197+
e: E,
198+
f: F,
199+
g: G,
200+
h: H,
201+
i: I,
202+
j: J,
203+
k: K
204+
);
205+
args_impl!(
206+
a: A,
207+
b: B,
208+
c: C,
209+
d: D,
210+
e: E,
211+
f: F,
212+
g: G,
213+
h: H,
214+
i: I,
215+
j: J,
216+
k: K,
217+
l: L
218+
);
219+
args_impl!(
220+
a: A,
221+
b: B,
222+
c: C,
223+
d: D,
224+
e: E,
225+
f: F,
226+
g: G,
227+
h: H,
228+
i: I,
229+
j: J,
230+
k: K,
231+
l: L,
232+
m: M
233+
);
234+
args_impl!(
235+
a: A,
236+
b: B,
237+
c: C,
238+
d: D,
239+
e: E,
240+
f: F,
241+
g: G,
242+
h: H,
243+
i: I,
244+
j: J,
245+
k: K,
246+
l: L,
247+
m: M,
248+
n: N
249+
);
250+
args_impl!(
251+
a: A,
252+
b: B,
253+
c: C,
254+
d: D,
255+
e: E,
256+
f: F,
257+
g: G,
258+
h: H,
259+
i: I,
260+
j: J,
261+
k: K,
262+
l: L,
263+
m: M,
264+
n: N,
265+
o: O
266+
);
267+
args_impl!(
268+
a: A,
269+
b: B,
270+
c: C,
271+
d: D,
272+
e: E,
273+
f: F,
274+
g: G,
275+
h: H,
276+
i: I,
277+
j: J,
278+
k: K,
279+
l: L,
280+
m: M,
281+
n: N,
282+
o: O,
283+
p: P
284+
);
285+
124286
#[cfg(test)]
125287
mod tests {
126288
use super::*;

0 commit comments

Comments
 (0)