Skip to main content

objc_rs/
macros.rs

1/**
2Gets a reference to a `Class`.
3
4Panics if no class with the given name can be found.
5To check for a class that may not exist, use `Class::get`.
6
7# Example
8``` no_run
9# #[macro_use] extern crate objc;
10# fn main() {
11let cls = class!(NSObject);
12# }
13```
14*/
15#[macro_export]
16macro_rules! class {
17    ($name:ident) => {{
18        #[allow(deprecated)]
19        #[inline(always)]
20        fn get_class(name: &str) -> Option<&'static $crate::runtime::Class> {
21            unsafe {
22                static CLASS: ::std::sync::atomic::AtomicUsize =
23                    ::std::sync::atomic::AtomicUsize::new(0);
24                // `Relaxed` should be fine since `objc_getClass` is thread-safe.
25                let ptr = CLASS.load(::std::sync::atomic::Ordering::Relaxed)
26                    as *const $crate::runtime::Class;
27                if ptr.is_null() {
28                    let cls = $crate::runtime::objc_getClass(name.as_ptr() as *const _);
29                    CLASS.store(cls as usize, ::std::sync::atomic::Ordering::Relaxed);
30                    if cls.is_null() { None } else { Some(&*cls) }
31                } else {
32                    Some(&*ptr)
33                }
34            }
35        }
36        match get_class(concat!(stringify!($name), '\0')) {
37            Some(cls) => cls,
38            None => panic!("Class with name {} could not be found", stringify!($name)),
39        }
40    }};
41}
42
43#[doc(hidden)]
44#[macro_export]
45macro_rules! sel_impl {
46    // Declare a function to hide unsafety, otherwise we can trigger the
47    // unused_unsafe lint; see rust-lang/rust#8472
48    ($name:expr) => {{
49        #[allow(deprecated)]
50        #[inline(always)]
51        fn register_sel(name: &str) -> $crate::runtime::Sel {
52            unsafe {
53                static SEL: ::std::sync::atomic::AtomicUsize =
54                    ::std::sync::atomic::AtomicUsize::new(0);
55                let ptr = SEL.load(::std::sync::atomic::Ordering::Relaxed)
56                    as *const ::std::os::raw::c_void;
57                // It should be fine to use `Relaxed` ordering here because `sel_registerName` is
58                // thread-safe.
59                if ptr.is_null() {
60                    let sel = $crate::runtime::sel_registerName(name.as_ptr() as *const _);
61                    SEL.store(
62                        sel.as_ptr() as usize,
63                        ::std::sync::atomic::Ordering::Relaxed,
64                    );
65                    sel
66                } else {
67                    $crate::runtime::Sel::from_ptr(ptr)
68                }
69            }
70        }
71        register_sel($name)
72    }};
73}
74
75/**
76Registers a selector, returning a `Sel`.
77
78# Example
79```
80# #[macro_use] extern crate objc;
81# fn main() {
82let sel = sel!(description);
83let sel = sel!(setObject:forKey:);
84# }
85```
86*/
87#[macro_export]
88macro_rules! sel {
89    ($name:ident) => ({sel_impl!(concat!(stringify!($name), '\0'))});
90    ($($name:ident :)+) => ({sel_impl!(concat!($(stringify!($name), ':'),+, '\0'))});
91}
92
93/**
94Sends a message to an object.
95
96The first argument can be any type that dereferences to a type that implements
97`Message`, like a reference, pointer, or an `Id`.
98The syntax is similar to the message syntax in Objective-C.
99Variadic arguments are not currently supported.
100
101# Example
102``` no_run
103# #[macro_use] extern crate objc;
104# use objc::runtime::Object;
105# fn main() {
106# unsafe {
107let obj: *mut Object;
108# let obj: *mut Object = 0 as *mut Object;
109let description: *const Object = msg_send![obj, description];
110let _: () = msg_send![obj, setArg1:1 arg2:2];
111# }
112# }
113```
114*/
115#[macro_export]
116macro_rules! msg_send {
117    (super($obj:expr, $superclass:expr), $name:ident) => ({
118        let sel = sel!($name);
119        let result;
120        match $crate::__send_super_message(&*$obj, $superclass, sel, ()) {
121            Err(s) => panic!("{}", s),
122            Ok(r) => result = r,
123        }
124        result
125    });
126    (super($obj:expr, $superclass:expr), $($name:ident : $arg:expr)+) => ({
127        let sel = sel!($($name:)+);
128        let result;
129        match $crate::__send_super_message(&*$obj, $superclass, sel, ($($arg,)*)) {
130            Err(s) => panic!("{}", s),
131            Ok(r) => result = r,
132        }
133        result
134    });
135    ($obj:expr, $name:ident) => ({
136        let sel = sel!($name);
137        let result;
138        match $crate::__send_message(&*$obj, sel, ()) {
139            Err(s) => panic!("{}", s),
140            Ok(r) => result = r,
141        }
142        result
143    });
144    ($obj:expr, $($name:ident : $arg:expr)+) => ({
145        let sel = sel!($($name:)+);
146        let result;
147        match $crate::__send_message(&*$obj, sel, ($($arg,)*)) {
148            Err(s) => panic!("{}", s),
149            Ok(r) => result = r,
150        }
151        result
152    });
153}