Skip to main content

objc_rs/message/
mod.rs

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