1 use std::ops::{Deref, DerefMut};
2 use std::os::raw::c_char;
3 use std::sync::{Once, ONCE_INIT};
4 
5 use declare::{ClassDecl, ProtocolDecl};
6 use runtime::{Class, Object, Protocol, Sel, self};
7 use {Encode, Encoding};
8 
9 pub struct CustomObject {
10     obj: *mut Object,
11 }
12 
13 impl CustomObject {
new(class: &Class) -> Self14     fn new(class: &Class) -> Self {
15         let obj = unsafe {
16             runtime::class_createInstance(class, 0)
17         };
18         CustomObject { obj: obj }
19     }
20 }
21 
22 impl Deref for CustomObject {
23     type Target = Object;
24 
deref(&self) -> &Object25     fn deref(&self) -> &Object {
26         unsafe { &*self.obj }
27     }
28 }
29 
30 impl DerefMut for CustomObject {
deref_mut(&mut self) -> &mut Object31     fn deref_mut(&mut self) -> &mut Object {
32         unsafe { &mut *self.obj }
33     }
34 }
35 
36 impl Drop for CustomObject {
drop(&mut self)37     fn drop(&mut self) {
38         unsafe {
39             runtime::object_dispose(self.obj);
40         }
41     }
42 }
43 
44 #[derive(Eq, PartialEq)]
45 pub struct CustomStruct {
46     pub a: u64,
47     pub b: u64,
48     pub c: u64,
49     pub d: u64,
50 }
51 
52 unsafe impl Encode for CustomStruct {
encode() -> Encoding53     fn encode() -> Encoding {
54         let mut code = "{CustomStruct=".to_owned();
55         for _ in 0..4 {
56             code.push_str(u64::encode().as_str());
57         }
58         code.push_str("}");
59         unsafe {
60             Encoding::from_str(&code)
61         }
62     }
63 }
64 
custom_class() -> &'static Class65 pub fn custom_class() -> &'static Class {
66     static REGISTER_CUSTOM_CLASS: Once = ONCE_INIT;
67 
68     REGISTER_CUSTOM_CLASS.call_once(|| {
69         // The runtime will call this method, so it has to be implemented
70         extern fn custom_obj_class_initialize(_this: &Class, _cmd: Sel) { }
71 
72         let mut decl = ClassDecl::root("CustomObject", custom_obj_class_initialize).unwrap();
73         let proto = custom_protocol();
74 
75         decl.add_protocol(proto);
76         decl.add_ivar::<u32>("_foo");
77 
78         extern fn custom_obj_set_foo(this: &mut Object, _cmd: Sel, foo: u32) {
79             unsafe { this.set_ivar::<u32>("_foo", foo); }
80         }
81 
82         extern fn custom_obj_get_foo(this: &Object, _cmd: Sel) -> u32 {
83             unsafe { *this.get_ivar::<u32>("_foo") }
84         }
85 
86         extern fn custom_obj_get_struct(_this: &Object, _cmd: Sel) -> CustomStruct {
87             CustomStruct { a: 1, b: 2, c: 3, d: 4 }
88         }
89 
90         extern fn custom_obj_class_method(_this: &Class, _cmd: Sel) -> u32 {
91             7
92         }
93 
94         extern fn custom_obj_set_bar(this: &mut Object, _cmd: Sel, bar: u32) {
95             unsafe { this.set_ivar::<u32>("_foo", bar) ;}
96         }
97 
98         extern fn custom_obj_add_number_to_number(_this: &Class, _cmd: Sel, fst: i32, snd: i32) -> i32 {
99             fst + snd
100         }
101 
102         unsafe {
103             let set_foo: extern fn(&mut Object, Sel, u32) = custom_obj_set_foo;
104             decl.add_method(sel!(setFoo:), set_foo);
105             let get_foo: extern fn(&Object, Sel) -> u32 = custom_obj_get_foo;
106             decl.add_method(sel!(foo), get_foo);
107             let get_struct: extern fn(&Object, Sel) -> CustomStruct = custom_obj_get_struct;
108             decl.add_method(sel!(customStruct), get_struct);
109             let class_method: extern fn(&Class, Sel) -> u32 = custom_obj_class_method;
110             decl.add_class_method(sel!(classFoo), class_method);
111 
112             let protocol_instance_method: extern fn(&mut Object, Sel, u32) = custom_obj_set_bar;
113             decl.add_method(sel!(setBar:), protocol_instance_method);
114             let protocol_class_method: extern fn(&Class, Sel, i32, i32) -> i32 = custom_obj_add_number_to_number;
115             decl.add_class_method(sel!(addNumber:toNumber:), protocol_class_method);
116         }
117 
118         decl.register();
119     });
120 
121     class!(CustomObject)
122 }
123 
custom_protocol() -> &'static Protocol124 pub fn custom_protocol() -> &'static Protocol {
125     static REGISTER_CUSTOM_PROTOCOL: Once = ONCE_INIT;
126 
127     REGISTER_CUSTOM_PROTOCOL.call_once(|| {
128         let mut decl = ProtocolDecl::new("CustomProtocol").unwrap();
129 
130         decl.add_method_description::<(i32,), ()>(sel!(setBar:), true);
131         decl.add_method_description::<(), *const c_char>(sel!(getName), false);
132         decl.add_class_method_description::<(i32, i32), i32>(sel!(addNumber:toNumber:), true);
133 
134         decl.register();
135     });
136 
137     Protocol::get("CustomProtocol").unwrap()
138 }
139 
custom_subprotocol() -> &'static Protocol140 pub fn custom_subprotocol() -> &'static Protocol {
141     static REGISTER_CUSTOM_SUBPROTOCOL: Once = ONCE_INIT;
142 
143     REGISTER_CUSTOM_SUBPROTOCOL.call_once(|| {
144         let super_proto = custom_protocol();
145         let mut decl = ProtocolDecl::new("CustomSubProtocol").unwrap();
146 
147         decl.add_protocol(super_proto);
148         decl.add_method_description::<(u32,), u32>(sel!(calculateFoo:), true);
149 
150         decl.register();
151     });
152 
153     Protocol::get("CustomSubProtocol").unwrap()
154 }
155 
custom_object() -> CustomObject156 pub fn custom_object() -> CustomObject {
157     CustomObject::new(custom_class())
158 }
159 
custom_subclass() -> &'static Class160 pub fn custom_subclass() -> &'static Class {
161     static REGISTER_CUSTOM_SUBCLASS: Once = ONCE_INIT;
162 
163     REGISTER_CUSTOM_SUBCLASS.call_once(|| {
164         let superclass = custom_class();
165         let mut decl = ClassDecl::new("CustomSubclassObject", superclass).unwrap();
166 
167         extern fn custom_subclass_get_foo(this: &Object, _cmd: Sel) -> u32 {
168             let foo: u32 = unsafe {
169                 msg_send![super(this, custom_class()), foo]
170             };
171             foo + 2
172         }
173 
174         unsafe {
175             let get_foo: extern fn(&Object, Sel) -> u32 = custom_subclass_get_foo;
176             decl.add_method(sel!(foo), get_foo);
177         }
178 
179         decl.register();
180     });
181 
182     class!(CustomSubclassObject)
183 }
184 
custom_subclass_object() -> CustomObject185 pub fn custom_subclass_object() -> CustomObject {
186     CustomObject::new(custom_subclass())
187 }
188