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