objc/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"))]
30#[path = "apple/mod.rs"]
31mod platform;
32#[cfg(not(any(target_os = "macos", target_os = "ios")))]
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 objc;
87    # use objc::runtime::{BOOL, Class, Object};
88    # use objc::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 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}