Skip to content

Commit 3524bdb

Browse files
committed
W. trait
1 parent a4da04c commit 3524bdb

File tree

4 files changed

+123
-22
lines changed

4 files changed

+123
-22
lines changed

objc2/examples/introspection.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ fn main() {
2020

2121
// Allocate an instance
2222
let obj: Id<Object, Owned> = unsafe {
23-
let obj: Id<Object, Owned> = msg_send_id![cls, alloc].unwrap();
23+
let obj = msg_send_id![cls, alloc];
2424
msg_send_id![obj, init].unwrap()
2525
};
2626
println!("NSObject address: {:p}", obj);

objc2/src/macros.rs

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -184,33 +184,25 @@ macro_rules! msg_send_id {
184184
const NAME: &[u8] = concat!($(stringify!($name), ':'),+).as_bytes();
185185
$crate::msg_send_id!(@__inner $obj, NAME, $($name: $arg),+)
186186
});
187-
(@__inner $obj:expr, $name:ident, $($sel:tt)+) => {{
188-
const IS_INIT: bool = $crate::__starts_with_str($name, b"init");
189-
const IS_RETAINED: bool = {
187+
(@__inner $obj:expr, $name:ident, $($rest:tt)+) => {{
188+
const ALLOC: bool = $crate::__starts_with_str($name, b"alloc");
189+
const INIT: bool = $crate::__starts_with_str($name, b"init");
190+
const RETAINED: bool = {
190191
$crate::__starts_with_str($name, b"alloc")
191192
|| $crate::__starts_with_str($name, b"new")
192193
|| $crate::__starts_with_str($name, b"copy")
193194
|| $crate::__starts_with_str($name, b"mutableCopy")
194195
|| $crate::__starts_with_str($name, b"init")
195196
};
196197

197-
::std::println!("IS_INIT: {}", IS_INIT);
198-
::std::println!("IS_RETAINED: {}", IS_RETAINED);
199-
200-
let result = if IS_INIT {
201-
// TODO: Ensure `obj` is Id here
202-
let obj = ::core::mem::ManuallyDrop::new($obj);
203-
$crate::msg_send![obj, $($sel)+]
204-
} else {
205-
$crate::msg_send![$obj, $($sel)+]
206-
};
207-
if IS_RETAINED {
208-
$crate::rc::Id::new(result)
209-
} else {
210-
// All code between the `msg_send!` and the `retain_autoreleased` must
211-
// be able to be optimized away for this to work.
212-
$crate::rc::Id::retain_autoreleased(result)
198+
use $crate::rc::{__MsgSendId, __Assert};
199+
let sel = $crate::sel!($($rest)+);
200+
let result;
201+
match <__Assert<ALLOC, INIT, RETAINED>>::__send_message($obj, sel, ()) {
202+
Err(s) => panic!("{}", s),
203+
Ok(r) => result = r,
213204
}
205+
result
214206
}};
215207
}
216208

@@ -232,6 +224,17 @@ pub const fn __starts_with_str(haystack: &[u8], needle: &[u8]) -> bool {
232224
#[cfg(test)]
233225
mod tests {
234226
use super::*;
227+
use crate::rc::{Id, Owned};
228+
use crate::runtime::Object;
229+
230+
#[test]
231+
fn test_macro() {
232+
let cls = class!(NSObject);
233+
let _obj: Id<Object, Owned> = unsafe {
234+
let obj = msg_send_id![cls, alloc];
235+
msg_send_id![obj, init].unwrap()
236+
};
237+
}
235238

236239
#[test]
237240
fn test_starts_with_str() {

objc2/src/rc/alloc.rs

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
use crate::{Message, RefEncode};
1+
use core::mem::ManuallyDrop;
2+
3+
use crate::runtime::{Class, Sel};
4+
use crate::{Message, MessageArguments, MessageError, MessageReceiver, RefEncode};
5+
6+
use super::{Id, Ownership};
27

38
/// TODO
49
#[repr(transparent)]
@@ -11,3 +16,96 @@ unsafe impl<T: ?Sized + RefEncode> RefEncode for Allocated<T> {
1116
}
1217

1318
unsafe impl<T: ?Sized + Message> Message for Allocated<T> {}
19+
20+
// #[doc(hidden)]
21+
// pub trait __MsgSendId<const IS_INIT: bool, T, U> {
22+
// fn __prepare(t: T) -> U;
23+
// }
24+
25+
// impl<T: ?Sized, O: Ownership>
26+
// __MsgSendId<true, Id<Allocated<T>, O>, ManuallyDrop<Id<Allocated<T>, O>>> for ()
27+
// {
28+
// fn __prepare(t: Id<Allocated<T>, O>) -> ManuallyDrop<Id<Allocated<T>, O>> {
29+
// ManuallyDrop::new(t)
30+
// }
31+
// }
32+
33+
// impl<T> __MsgSendId<false, T, T> for () {
34+
// fn __prepare(t: T) -> T {
35+
// t
36+
// }
37+
// }
38+
39+
#[doc(hidden)]
40+
pub struct __Assert<const ALLOC: bool, const INIT: bool, const RETAINED: bool> {}
41+
42+
#[doc(hidden)]
43+
pub trait __MsgSendId<T, U> {
44+
unsafe fn __send_message<A: MessageArguments>(
45+
obj: T,
46+
sel: Sel,
47+
args: A,
48+
) -> Result<U, MessageError>;
49+
}
50+
51+
impl<T: ?Sized + Message, O: Ownership> __MsgSendId<&'_ Class, Id<Allocated<T>, O>>
52+
for __Assert<true, false, true>
53+
{
54+
unsafe fn __send_message<A: MessageArguments>(
55+
cls: &Class,
56+
sel: Sel,
57+
args: A,
58+
) -> Result<Id<Allocated<T>, O>, MessageError> {
59+
unsafe {
60+
MessageReceiver::send_message(&cls, sel, args)
61+
.map(|r| Id::new(r).expect("Failed allocating"))
62+
}
63+
}
64+
}
65+
66+
impl<T: ?Sized + Message, O: Ownership> __MsgSendId<Id<Allocated<T>, O>, Option<Id<T, O>>>
67+
for __Assert<false, true, true>
68+
{
69+
unsafe fn __send_message<A: MessageArguments>(
70+
obj: Id<Allocated<T>, O>,
71+
sel: Sel,
72+
args: A,
73+
) -> Result<Option<Id<T, O>>, MessageError> {
74+
let obj = ManuallyDrop::new(obj);
75+
unsafe { MessageReceiver::send_message(&obj, sel, args).map(|r| Id::new(r)) }
76+
}
77+
}
78+
79+
impl<T: MessageReceiver, U: ?Sized + Message, O: Ownership> __MsgSendId<T, Option<Id<U, O>>>
80+
for __Assert<false, false, true>
81+
{
82+
unsafe fn __send_message<A: MessageArguments>(
83+
obj: T,
84+
sel: Sel,
85+
args: A,
86+
) -> Result<Option<Id<U, O>>, MessageError> {
87+
unsafe { MessageReceiver::send_message(&obj, sel, args).map(|r| Id::new(r)) }
88+
}
89+
}
90+
91+
impl<T: MessageReceiver, U: Message, O: Ownership> __MsgSendId<T, Option<Id<U, O>>>
92+
for __Assert<false, false, false>
93+
{
94+
unsafe fn __send_message<A: MessageArguments>(
95+
obj: T,
96+
sel: Sel,
97+
args: A,
98+
) -> Result<Option<Id<U, O>>, MessageError> {
99+
// All code between the message send and the `retain_autoreleased`
100+
// must be able to be optimized away for this to work.
101+
unsafe {
102+
MessageReceiver::send_message(&obj, sel, args).map(|r| Id::retain_autoreleased(r))
103+
}
104+
}
105+
}
106+
107+
// impl<T> __MsgSendId<T, T> for __Assert<false> {
108+
// fn __prepare(t: T) -> T {
109+
// t
110+
// }
111+
// }

objc2/src/rc/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ mod id_traits;
6363
mod ownership;
6464
mod weak_id;
6565

66-
pub use self::alloc::Allocated;
66+
pub use self::alloc::{Allocated, __Assert, __MsgSendId};
6767
pub use self::autorelease::{autoreleasepool, AutoreleasePool, AutoreleaseSafe};
6868
pub use self::id::Id;
6969
pub use self::id_traits::{DefaultId, SliceId, SliceIdMut};

0 commit comments

Comments
 (0)