makepad_objc_sys/message/mod.rs
1use std::any::Any;
2use std::error::Error;
3use std::fmt;
4use std::mem;
5
6use runtime::{Class, Imp, Object, Sel};
7use {Encode, EncodeArguments};
8
9#[cfg(feature = "exception")]
10macro_rules! objc_try {
11 ($b:block) => (
12 $crate::exception::try(|| $b).map_err(|exception|
13 if exception.is_null() {
14 MessageError("Uncaught exception nil".to_owned())
15 } else {
16 MessageError(format!("Uncaught exception {:?}", &**exception))
17 }
18 )
19 )
20}
21
22#[cfg(not(feature = "exception"))]
23macro_rules! objc_try {
24 ($b:block) => (Ok($b))
25}
26
27mod verify;
28
29#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos"))]
30#[path = "apple/mod.rs"]
31mod platform;
32#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "tvos")))]
33#[path = "gnustep.rs"]
34mod platform;
35
36use self::platform::{send_unverified, send_super_unverified};
37use self::verify::verify_message_signature;
38
39/// Specifies the superclass of an instance.
40#[repr(C)]
41pub struct Super {
42 /// Specifies an instance of a class.
43 pub receiver: *mut Object,
44 /// Specifies the particular superclass of the instance to message.
45 pub superclass: *const Class,
46}
47
48/// Types that may be sent Objective-C messages.
49/// For example: objects, classes, and blocks.
50pub unsafe trait Message {
51 /**
52 Sends a message to self with the given selector and arguments.
53
54 The correct version of `objc_msgSend` will be chosen based on the
55 return type. For more information, see Apple's documentation:
56 <https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html#//apple_ref/doc/uid/TP40001418-CH1g-88778>
57
58 If the selector is known at compile-time, it is recommended to use the
59 `msg_send!` macro rather than this method.
60 */
61 #[cfg(not(feature = "verify_message"))]
62 unsafe fn send_message<A, R>(&self, sel: Sel, args: A)
63 -> Result<R, MessageError>
64 where Self: Sized, A: MessageArguments, R: Any {
65 send_message(self, sel, args)
66 }
67
68 #[cfg(feature = "verify_message")]
69 unsafe fn send_message<A, R>(&self, sel: Sel, args: A)
70 -> Result<R, MessageError>
71 where Self: Sized, A: MessageArguments + EncodeArguments,
72 R: Any + Encode {
73 send_message(self, sel, args)
74 }
75
76 /**
77 Verifies that the argument and return types match the encoding of the
78 method for the given selector.
79
80 This will look up the encoding of the method for the given selector, `sel`,
81 and return a `MessageError` if any encodings differ for the arguments `A`
82 and return type `R`.
83
84 # Example
85 ``` no_run
86 # #[macro_use] extern crate makepad_objc_sys;
87 # use makepad_objc_sys::runtime::{BOOL, Class, Object};
88 # use makepad_objc_sys::Message;
89 # fn main() {
90 let obj: &Object;
91 # obj = unsafe { msg_send![class!(NSObject), new] };
92 let sel = sel!(isKindOfClass:);
93 // Verify isKindOfClass: takes one Class and returns a BOOL
94 let result = obj.verify_message::<(&Class,), BOOL>(sel);
95 assert!(result.is_ok());
96 # }
97 ```
98 */
99 fn verify_message<A, R>(&self, sel: Sel) -> Result<(), MessageError>
100 where Self: Sized, A: EncodeArguments, R: Encode {
101 let obj = unsafe { &*(self as *const _ as *const Object) };
102 verify_message_signature::<A, R>(obj.class(), sel)
103 }
104}
105
106unsafe impl Message for Object { }
107
108unsafe impl Message for Class { }
109
110/// Types that may be used as the arguments of an Objective-C message.
111pub trait MessageArguments: Sized {
112 /// Invoke an `Imp` with the given object, selector, and arguments.
113 ///
114 /// This method is the primitive used when sending messages and should not
115 /// be called directly; instead, use the `msg_send!` macro or, in cases
116 /// with a dynamic selector, the `Message::send_message` method.
117 unsafe fn invoke<R>(imp: Imp, obj: *mut Object, sel: Sel, args: Self) -> R
118 where R: Any;
119}
120
121macro_rules! message_args_impl {
122 ($($a:ident : $t:ident),*) => (
123 impl<$($t),*> MessageArguments for ($($t,)*) {
124 unsafe fn invoke<R>(imp: Imp, obj: *mut Object, sel: Sel, ($($a,)*): Self) -> R
125 where R: Any {
126 let imp: unsafe extern "C" fn(*mut Object, Sel $(, $t)*) -> R =
127 mem::transmute(imp);
128 imp(obj, sel $(, $a)*)
129 }
130 }
131 );
132}
133
134message_args_impl!();
135message_args_impl!(a: A);
136message_args_impl!(a: A, b: B);
137message_args_impl!(a: A, b: B, c: C);
138message_args_impl!(a: A, b: B, c: C, d: D);
139message_args_impl!(a: A, b: B, c: C, d: D, e: E);
140message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
141message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
142message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
143message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
144message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
145message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
146message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);
147
148/**
149An error encountered while attempting to send a message.
150
151Currently, an error may be returned in two cases:
152
153* an Objective-C exception is thrown and the `exception` feature is enabled
154* the encodings of the arguments do not match the encoding of the method
155 and the `verify_message` feature is enabled
156*/
157#[derive(Debug)]
158pub struct MessageError(String);
159
160impl fmt::Display for MessageError {
161 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162 fmt::Display::fmt(&self.0, f)
163 }
164}
165
166impl Error for MessageError {
167 fn description(&self) -> &str {
168 &self.0
169 }
170}
171
172#[doc(hidden)]
173#[inline(always)]
174#[cfg(not(feature = "verify_message"))]
175pub unsafe fn send_message<T, A, R>(obj: *const T, sel: Sel, args: A)
176 -> Result<R, MessageError>
177 where T: Message, A: MessageArguments, R: Any {
178 send_unverified(obj, sel, args)
179}
180
181#[doc(hidden)]
182#[inline(always)]
183#[cfg(feature = "verify_message")]
184pub unsafe fn send_message<T, A, R>(obj: *const T, sel: Sel, args: A)
185 -> Result<R, MessageError>
186 where T: Message, A: MessageArguments + EncodeArguments,
187 R: Any + Encode {
188 let cls = if obj.is_null() {
189 return Err(MessageError(format!("Messaging {:?} to nil", sel)));
190 } else {
191 (*(obj as *const Object)).class()
192 };
193
194 verify_message_signature::<A, R>(cls, sel).and_then(|_| {
195 send_unverified(obj, sel, args)
196 })
197}
198
199#[doc(hidden)]
200#[inline(always)]
201#[cfg(not(feature = "verify_message"))]
202pub unsafe fn send_super_message<T, A, R>(obj: *const T, superclass: &Class,
203 sel: Sel, args: A) -> Result<R, MessageError>
204 where T: Message, A: MessageArguments, R: Any {
205 send_super_unverified(obj, superclass, sel, args)
206}
207
208#[doc(hidden)]
209#[inline(always)]
210#[cfg(feature = "verify_message")]
211pub unsafe fn send_super_message<T, A, R>(obj: *const T, superclass: &Class,
212 sel: Sel, args: A) -> Result<R, MessageError>
213 where T: Message, A: MessageArguments + EncodeArguments,
214 R: Any + Encode {
215 if obj.is_null() {
216 return Err(MessageError(format!("Messaging {:?} to nil", sel)));
217 }
218
219 verify_message_signature::<A, R>(superclass, sel).and_then(|_| {
220 send_super_unverified(obj, superclass, sel, args)
221 })
222}
223/*
224#[cfg(test)]
225mod tests {
226 use test_utils;
227 use runtime::Object;
228 use super::Message;
229
230 #[test]
231 fn test_send_message() {
232 let obj = test_utils::custom_object();
233 let result: u32 = unsafe {
234 let _: () = msg_send![obj, setFoo:4u32];
235 msg_send![obj, foo]
236 };
237 assert!(result == 4);
238 }
239
240 #[test]
241 fn test_send_message_stret() {
242 let obj = test_utils::custom_object();
243 let result: test_utils::CustomStruct = unsafe {
244 msg_send![obj, customStruct]
245 };
246 let expected = test_utils::CustomStruct { a: 1, b:2, c: 3, d: 4 };
247 assert!(result == expected);
248 }
249
250 #[cfg(not(feature = "verify_message"))]
251 #[test]
252 fn test_send_message_nil() {
253 let nil: *mut Object = ::std::ptr::null_mut();
254 let result: usize = unsafe {
255 msg_send![nil, hash]
256 };
257 assert!(result == 0);
258
259 let result: *mut Object = unsafe {
260 msg_send![nil, description]
261 };
262 assert!(result.is_null());
263
264 let result: f64 = unsafe {
265 msg_send![nil, doubleValue]
266 };
267 assert!(result == 0.0);
268 }
269
270 #[test]
271 fn test_send_message_super() {
272 let obj = test_utils::custom_subclass_object();
273 let superclass = test_utils::custom_class();
274 unsafe {
275 let _: () = msg_send![obj, setFoo:4u32];
276 let foo: u32 = msg_send![super(obj, superclass), foo];
277 assert!(foo == 4);
278
279 // The subclass is overriden to return foo + 2
280 let foo: u32 = msg_send![obj, foo];
281 assert!(foo == 6);
282 }
283 }
284
285 #[test]
286 fn test_verify_message() {
287 let obj = test_utils::custom_object();
288 assert!(obj.verify_message::<(), u32>(sel!(foo)).is_ok());
289 assert!(obj.verify_message::<(u32,), ()>(sel!(setFoo:)).is_ok());
290
291 // Incorrect types
292 assert!(obj.verify_message::<(), u64>(sel!(setFoo:)).is_err());
293 // Unimplemented selector
294 assert!(obj.verify_message::<(u32,), ()>(sel!(setFoo)).is_err());
295 }
296}*/