Mercurial > projects > dstep
comparison dstep/objc/bridge/Bridge.d @ 16:19885b43130e
Huge update, the bridge actually works now
author | Jacob Carlborg <doob@me.com> |
---|---|
date | Sun, 03 Jan 2010 22:06:11 +0100 |
parents | 07194b026fa4 |
children | b2693af5a569 |
comparison
equal
deleted
inserted
replaced
15:7ff919f595d5 | 16:19885b43130e |
---|---|
8 | 8 |
9 version (Tango) | 9 version (Tango) |
10 { | 10 { |
11 import tango.core.Memory; | 11 import tango.core.Memory; |
12 import tango.core.Traits : ParameterTupleOf, ReturnTypeOf; | 12 import tango.core.Traits : ParameterTupleOf, ReturnTypeOf; |
13 | |
14 alias GC.addRoot addRoot; | |
15 } | 13 } |
16 | 14 |
17 else | 15 else |
18 { | 16 { |
19 import std.gc : addRoot; | 17 import GC = std.gc : addRoot; |
20 import std.traits : ParameterTypeTuple, ReturnType; | 18 import std.traits : ParameterTypeTuple, ReturnType; |
21 | 19 |
22 alias ReturnType ReturnTypeOf; | 20 alias ReturnType ReturnTypeOf; |
23 alias ParameterTypeTuple ParameterTupleOf; | 21 alias ParameterTypeTuple ParameterTupleOf; |
24 } | 22 } |
25 | 23 |
26 import dstep.internal.String; | 24 import dstep.internal.String; |
27 import dstep.internal.Tuple; | |
28 import dstep.internal.Version; | 25 import dstep.internal.Version; |
29 import dstep.objc.bridge.Capsule; | 26 import dstep.objc.bridge.Capsule; |
30 import dstep.objc.bridge.ClassInitializer; | 27 import dstep.objc.bridge.ClassInitializer; |
28 import dstep.objc.bridge.Type; | |
31 import dstep.objc.bridge.TypeEncoding; | 29 import dstep.objc.bridge.TypeEncoding; |
32 import dstep.objc.bridge.Wrapper; | 30 import dstep.objc.bridge.Wrapper; |
33 import dstep.objc.message; | 31 import dstep.objc.message; |
34 import dstep.objc.objc; | 32 import dstep.objc.objc; |
35 import dstep.objc.runtime; | 33 import dstep.objc.runtime; |
36 | 34 |
37 /** | 35 /** |
38 * Builds a string representing a selector out of the given function | 36 * Builds a string representing a selector out of the given method |
39 * | 37 * |
40 * It will build the string like this: | 38 * It will build the string using the parameter names as a part of the selector, |
41 * | 39 * like this: |
42 * --- | 40 * |
43 * foo (int x, int y); // foo:y: | 41 * Examples: |
44 * bar (); // bar | 42 * --- |
45 * fooBar (int x); // fooBar: | 43 * foo (int x, int y); |
46 * --- | 44 * bar (); |
47 * | 45 * fooBar (int x); |
48 * Params: | 46 * |
49 * func = the function alias to build the selector of | 47 * static assert(selectorAsString!(foo) == "foo:y:"); |
48 * static assert(selectorAsString!(bar) == "bar"); | |
49 * static assert(selectorAsString!(fooBar) == "fooBar:"); | |
50 * --- | |
51 * | |
52 * Params: | |
53 * method = the method alias to build the selector of | |
50 * | 54 * |
51 * Returns: a string representing the selector | 55 * Returns: a string representing the selector |
52 */ | 56 */ |
53 template selector (alias func) | 57 template selectorAsString (alias method) |
54 { | 58 { |
55 const selector = buildSelector!(func); | 59 const selectorAsString = buildSelector!(method); |
56 } | 60 } |
57 | 61 |
58 template ObjcWrap () | 62 /** |
59 { | 63 * Registers a method with the Objective-C runtime system, |
60 mixin ObjcWrap!(this.stringof); | 64 * maps the method name to a selector, and returns the selector value. |
61 } | 65 * |
62 | 66 * You must register a method name with the Objective-C runtime system to obtain |
63 template ObjcWrap (string name) | 67 * the method’s selector before you can add the method to a class definition. |
64 { | 68 * If the method name has already been registered, this function simply returns |
65 private | 69 * the selector. |
66 { | 70 * |
67 import dstep.objc.bridge.ClassInitializer : ObjcSubclassInitializer, subclassInit; | 71 * Examples: |
68 import dstep.objc.objc : Class, id, IMP, SEL; | 72 * --- |
69 | 73 * SEL sel = selector!("foo:"); |
70 static Class objcClass_; | 74 * --- |
71 static Class objcSuperClass_; | 75 * |
72 } | 76 * Params: |
73 | 77 * str = the string to register |
74 this () | 78 * |
75 { | 79 * Returns: a pointer of type SEL specifying the selector for the named method. |
76 objcObject = invokeObjcSelfClass!(id, "alloc"); | 80 */ |
77 id ret = invokeObjcSelf!(id, "init"); | 81 SEL selector (string str) () |
78 | 82 { |
79 if (ret) | 83 return sel.registerName!(str); |
80 objcObject = ret; | 84 } |
81 | 85 |
82 dObject = this; | 86 /** |
83 } | 87 * Registers a method with the Objective-C runtime system, |
84 | 88 * maps the method name to a selector, and returns the selector value. |
85 this (id object) | 89 * |
90 * Using selectorAsString to get the string representation of the selector. | |
91 * | |
92 * You must register a method name with the Objective-C runtime system to obtain | |
93 * the method’s selector before you can add the method to a class definition. | |
94 * If the method name has already been registered, this function simply returns | |
95 * the selector. | |
96 * | |
97 * Examples: | |
98 * --- | |
99 * foo (int x); | |
100 * SEL sel = selector!(foo); | |
101 * --- | |
102 * | |
103 * Params: | |
104 * method = the method to register | |
105 * | |
106 * Returns: a pointer of type SEL specifying the selector for the named method. | |
107 */ | |
108 SEL selector (alias method) () | |
109 { | |
110 return sel.registerName!(selectorAsString!(method)); | |
111 } | |
112 | |
113 /** | |
114 * All Objective-C wrappers should mix in this string. | |
115 * | |
116 * Mixes in: | |
117 * $(UL | |
118 * $(LI $(D_PSYMBOL __objcClass): a class variable representing the Objective-C class) | |
119 * $(LI $(D_PSYMBOL __objcSuperClass): a class variable representing the Objective-C super class) | |
120 * $(LI A constructor taking an Objective-C instance) | |
121 * $(LI $(D_PSYMBOL dstep.objc.bridge.ClassInitializer.ObjcSubclassInitializer)) | |
122 * ) | |
123 * | |
124 * Examples: | |
125 * --- | |
126 * class AppController : NSObject | |
127 * { | |
128 * mixin(ObjcWrap); | |
129 * } | |
130 * --- | |
131 */ | |
132 const ObjcWrap = "static private dstep.objc.objc.Class __objcClass; | |
133 static private dstep.objc.objc.Class __objcSuperClass; | |
134 | |
135 this (dstep.objc.objc.id object) | |
86 { | 136 { |
87 super(object); | 137 super(object); |
88 } | 138 } |
89 | 139 |
90 /*static typeof(this) alloc () | 140 static typeof(this) alloc () |
91 { | 141 { |
92 return invokeObjcSelfClass!(typeof(this), "alloc"); | 142 return invokeObjcSelfClass!(typeof(this), \"alloc\"); |
93 }*/ | 143 } |
94 | 144 |
95 /*typeof(this) init () | 145 mixin dstep.objc.bridge.ClassInitializer.ObjcSubclassInitializer!(this.stringof, super.stringof);"; |
96 { | 146 |
97 id ret = invokeObjcSelf!(id, "init"); | 147 /** |
98 | 148 * All Objective-C wrappers should mix in this string. |
99 if (!ret) | 149 * |
100 return null; | 150 * Mixes in: |
101 | 151 * $(UL |
102 if (ret is objcObject) | 152 * $(LI $(D_PSYMBOL __objcClass): a class variable representing the Objective-C class) |
103 { | 153 * $(LI $(D_PSYMBOL __objcSuperClass): a class variable representing the Objective-C super class) |
104 dObject = this; | 154 * $(LI A constructor taking an Objective-C instance) |
105 return this; | 155 * $(LI $(D_PSYMBOL dstep.objc.bridge.ClassInitializer.ObjcSubclassInitializer)) |
106 } | 156 * ) |
107 | 157 * |
108 auto object = new typeof(this) (ret); | 158 * Examples: |
109 object.dObject = this; | 159 * --- |
110 | 160 * class NSString : NSObject |
111 return object; | 161 * { |
112 }*/ | 162 * mixin(ObjcClusterWrap); |
113 | 163 * } |
114 mixin ObjcSubclassInitializer!("D_" ~ name, name); | 164 * --- |
115 } | 165 */ |
116 | 166 const ObjcClusterWrap = "static private dstep.objc.objc.Class __objcClass; |
167 static private dstep.objc.objc.Class __objcSuperClass; | |
168 | |
169 this (dstep.objc.objc.id object) | |
170 { | |
171 super(object); | |
172 } | |
173 | |
174 static typeof(this) alloc () | |
175 { | |
176 return invokeObjcSuperClass!(typeof(this), \"alloc\"); | |
177 } | |
178 | |
179 mixin dstep.objc.bridge.ClassInitializer.ObjcSubclassInitializer!(this.stringof, super.stringof);"; | |
180 | |
181 /** | |
182 * This $(D_KEYWORD struct) represents an Objective-C method declaration. | |
183 * | |
184 * Examples: | |
185 * --- | |
186 * class C : NSObject | |
187 * { | |
188 * void foo (int x) {} | |
189 * ObjcMethodDeclaration!(foo, void, "foo", int) objcMethodDecl; | |
190 * } | |
191 * --- | |
192 * | |
193 * Params: | |
194 * imp = the D method | |
195 * R = the return type of the method | |
196 * name = the name of the method | |
197 * ARGS = the argument types of the method | |
198 */ | |
117 struct ObjcMethodDeclaration (alias imp, R, string name, ARGS...) | 199 struct ObjcMethodDeclaration (alias imp, R, string name, ARGS...) |
118 { | 200 { |
119 alias imp methodImp; | 201 dstep.objc.objc.IMP methodImp = cast(dstep.objc.objc.IMP) &imp; |
120 alias R returnType; | 202 alias R returnType; |
121 const string methodName = name; | 203 const string methodName = name; |
122 alias ARGS argsType; | 204 alias ARGS argsType; |
123 } | 205 } |
124 | 206 |
207 /** | |
208 * Binds a selector to an instance method. | |
209 * | |
210 * This will create a receiver function which will forward the call to $(D_PARAM method), | |
211 * decapsulating arguments and encapsulating the return value as appropriate. | |
212 * This $(D_KEYWORD template) will use the buildSelector $(D_KEYWORD template) to build | |
213 * the selector. It will automatically infer the return type and the argument types | |
214 * of the method. | |
215 * | |
216 * Mixes in: ObjcBindMethod | |
217 * | |
218 * Examples: | |
219 * --- | |
220 * class AppController : NSObject | |
221 * { | |
222 * void foo () {} | |
223 * mixin ObjcBindMethod!(foo); | |
224 * } | |
225 * --- | |
226 * | |
227 * Params: | |
228 * method = the method to bind | |
229 */ | |
125 template ObjcBindMethod (alias method) | 230 template ObjcBindMethod (alias method) |
126 { | 231 { |
127 import dstep.objc.bridge.TypeEncoding : buildSelector, encode; | 232 mixin ObjcBindMethod!(method, dstep.objc.bridge.TypeEncoding.buildSelector!(method)); |
128 | 233 } |
129 mixin ObjcBindMethod!(method, buildSelector!(method)); | 234 |
130 } | 235 /** |
131 | 236 * Binds a selector to an instance method. |
237 * | |
238 * This will create a receiver function which will forward the call to $(D_PARAM method), | |
239 * decapsulating arguments and encapsulating the return value as appropriate. | |
240 * It will automatically infer the return type and the argument types | |
241 * of the method. | |
242 * | |
243 * Mixes in: ObjcBindMethod | |
244 * | |
245 * Examples: | |
246 * --- | |
247 * class AppController : NSObject | |
248 * { | |
249 * void foo () {} | |
250 * mixin ObjcBindMethod!(foo, "foo"); | |
251 * } | |
252 * --- | |
253 * | |
254 * Params: | |
255 * method = the method to bind | |
256 * selector = the selector to bind the method to | |
257 */ | |
132 template ObjcBindMethod (alias method, string selector) | 258 template ObjcBindMethod (alias method, string selector) |
133 { | 259 { |
134 mixin ObjcBindMethod!(method, ReturnTypeOf!(method), selector, ParameterTupleOf!(method)); | 260 version (Tango) |
135 } | 261 mixin ObjcBindMethod!(method, tango.core.Traits.ReturnTypeOf!(method), selector, tango.core.Traits.ParameterTupleOf!(method)); |
136 | 262 |
263 else | |
264 mixin ObjcBindMethod!(method, std.traits.ReturnType!(method), selector, std.traits.ParameterTypeTuple!(method)); | |
265 } | |
266 | |
267 /** | |
268 * Binds a selector to an instance method. | |
269 * | |
270 * This will create a receiver method which will forward the call to $(D_PARAM method), | |
271 * decapsulating arguments and encapsulating the return value as appropriate. | |
272 * | |
273 * Examples: | |
274 * --- | |
275 * class AppController : NSObject | |
276 * { | |
277 * int foo (int x) | |
278 * { | |
279 * return x; | |
280 * } | |
281 * | |
282 * mixin ObjcBindMethod!(foo, int, "foo:", int); | |
283 * } | |
284 * --- | |
285 * | |
286 * Params: | |
287 * method = the method to bind | |
288 * R = the return type of the method | |
289 * selector = the selector to bind the method to | |
290 * ARGS = the argument types of the method | |
291 */ | |
137 template ObjcBindMethod (alias method, R, string selector, ARGS...) | 292 template ObjcBindMethod (alias method, R, string selector, ARGS...) |
138 { | 293 { |
139 private | 294 private |
140 { | 295 { |
141 import dstep.objc.bridge.Capsule : decapsule, encapsule, isCapsule; | 296 /** |
142 import dstep.objc.bridge.Type : needsEncapsulation, ObjcType; | 297 * Resolves the virtual call |
143 import dstep.internal.Tuple; | 298 * |
144 | 299 * Returns: a $(D_KEYWORD delegate) to the binded method |
145 ObjcMethodDeclaration!(method, R, selector, ARGS) objcMethodDeclaration; | 300 */ |
146 | 301 R delegate (ARGS) __resolveVirtualCall () |
147 R delegate (ARGS) resolveVirtualCall () | 302 { |
148 { | 303 return &method; |
149 return null; | 304 } |
150 } | 305 |
151 | 306 /// A type tuple with all the encapsulated types |
152 alias ReplaceAllClasses!(id, ARGS) ObjcArgs; | 307 alias dstep.objc.bridge.Type.ObjcTypes!(ARGS) __ObjcArgs; |
153 | 308 |
154 static ObjcType!(R) forwardVirtualCall (id self, SEL cmd, ObjcArgs objcArgs) | 309 /** |
310 * The receiver method, this will be the method called from the Objective-C side | |
311 * | |
312 * Params: | |
313 * self = the Objective-C instance to call the method on | |
314 * cmd = the Objective-C selector representing the method to call | |
315 * objcArgs = the encapsulated arguments to the binded method | |
316 * | |
317 * Returns: whatever the binded method returns, encapsulated | |
318 */ | |
319 extern (C) static dstep.objc.bridge.Type.ObjcType!(R) __forwardVirtualCall (dstep.objc.objc.id self, dstep.objc.objc.SEL cmd, __ObjcArgs objcArgs) | |
155 in | 320 in |
156 { | 321 { |
157 assert(isCapsule(self)); | 322 assert(dstep.objc.bridge.Capsule.isCapsule(self)); |
158 } | 323 } |
159 body | 324 body |
160 { | 325 { |
161 R delegate (ARGS) dg; | 326 R delegate (ARGS) delegate () dg; |
162 dg.funcptr = &method; | 327 dg.ptr = cast(void*) dstep.objc.bridge.Capsule.decapsule!(typeof(this))(self); |
163 dg.ptr = Bridge.getDObject(self); | 328 dg.funcptr = &__resolveVirtualCall; |
164 | |
165 ARGS args; | 329 ARGS args; |
166 | 330 |
167 foreach (i, a ; objcArgs) | 331 foreach (i, a ; objcArgs) |
168 { | 332 { |
169 alias typeof(args[i]) ArgType; | 333 alias typeof(args[i]) ArgType; |
170 | 334 args[i] = dstep.objc.bridge.Capsule.decapsule!(ArgType)(a); |
171 args[i] = decapsule!(ArgType)(a); | |
172 } | 335 } |
173 | 336 |
174 static if (is(R == void)) | 337 static if (is(R == void)) |
175 dg(args); | 338 dg()(args); |
176 | 339 |
177 else | 340 else |
178 return encapsule!(R)(dg(args)); | 341 return dstep.objc.bridge.Capsule.encapsule!(R)(dg()(args)); |
179 } | 342 } |
180 } | 343 |
181 } | 344 /// The Objective-C method declaration for the binded method |
182 | 345 ObjcMethodDeclaration!(__forwardVirtualCall, R, selector, ARGS) __objcMethodDeclaration; |
346 } | |
347 } | |
348 | |
349 /** | |
350 * Binds a selector to a class (static) method. | |
351 * | |
352 * This will create a receiver function which will forward the call to $(D_PARAM method), | |
353 * decapsulating arguments and encapsulating the return value as appropriate. | |
354 * This $(D_KEYWORD template) will use the buildSelector $(D_KEYWORD template) | |
355 * to build the selector. It will automatically infer the return type and the | |
356 * argument types of the method. | |
357 * | |
358 * Mixes in: $(D_PSYMBOL ObjcBindClassMethod) | |
359 * | |
360 * Examples: | |
361 * --- | |
362 * class AppController : NSObject | |
363 * { | |
364 * static void foo () {} | |
365 * mixin ObjcBindClassMethod!(foo); | |
366 * } | |
367 * --- | |
368 * | |
369 * Params: | |
370 * method = the method to bind | |
371 */ | |
372 template ObjcBindClassMethod (alias method) | |
373 { | |
374 mixin ObjcBindClassMethod!(method, dstep.objc.bridge.TypeEncoding.buildSelector!(method)); | |
375 } | |
376 | |
377 /** | |
378 * Binds a selector to a class (static) method. | |
379 * | |
380 * This will create a receiver function which will forward the call to $(D_PARAM method), | |
381 * decapsulating arguments and encapsulating the return value as appropriate. | |
382 * It will automatically infer the return type and the argument types | |
383 * of the method. | |
384 * | |
385 * Mixes in: $(D_PSYMBOL ObjcBindClassMethod) | |
386 * | |
387 * Examples: | |
388 * --- | |
389 * class AppController : NSObject | |
390 * { | |
391 * static void foo () {} | |
392 * mixin ObjcBindClassMethod!(foo, "foo"); | |
393 * } | |
394 * --- | |
395 * | |
396 * Params: | |
397 * method = the method to bind | |
398 * selector = the selector to bind the method to | |
399 */ | |
183 template ObjcBindClassMethod (alias method, string selector) | 400 template ObjcBindClassMethod (alias method, string selector) |
184 { | 401 { |
185 mixin ObjcBindClassMethod!(method, ReturnTypeOf!(method), selector, ParameterTupleOf!(method)); | 402 version (Tango) |
186 } | 403 mixin ObjcBindClassMethod!(method, tango.core.Traits.ReturnTypeOf!(method), selector, tango.core.Traits.ParameterTupleOf!(method)); |
187 | 404 |
405 else | |
406 mixin ObjcBindClassMethod!(method, std.traits.ReturnType!(method), selector, std.traits.ParameterTypeTuple!(method)); | |
407 } | |
408 | |
409 /** | |
410 * Binds a selector to a class (static) method. | |
411 * | |
412 * This will create a receiver method which will forward the call to $(D_PARAM method), | |
413 * decapsulating arguments and encapsulating the return value as appropriate. | |
414 * | |
415 * Examples: | |
416 * --- | |
417 * class AppController : NSObject | |
418 * { | |
419 * static int foo (int x) | |
420 * { | |
421 * return x; | |
422 * } | |
423 * | |
424 * mixin ObjcBindClassMethod!(foo, int, "foo:", int); | |
425 * } | |
426 * --- | |
427 * | |
428 * Params: | |
429 * method = the method to bind | |
430 * R = the return type of the method | |
431 * selector = the selector to bind the method to | |
432 * ARGS = the argument types of the method | |
433 */ | |
188 template ObjcBindClassMethod (alias method, R, string selector, ARGS...) | 434 template ObjcBindClassMethod (alias method, R, string selector, ARGS...) |
189 { | 435 { |
190 private | 436 private |
191 { | 437 { |
192 import dstep.objc.bridge.Capsule : decapsule, encapsule, isCapsule, needsEncapsulation, ObjcType; | 438 /// A type tuple with all the encapsulated types |
193 import dstep.internal.Tuple; | 439 alias dstep.objc.bridge.Type.ObjcTypes!(ARGS) __ObjcArgs; |
194 | 440 |
195 ObjcMethodDeclaration!(method, R, selector, ARGS) objcClassMethodDeclaration; | 441 /** |
196 | 442 * The receiver method, this will be the method called from the Objective-C side |
197 alias ReplaceAllClasses!(id, ARGS) ObjcArgs; | 443 * |
198 | 444 * Params: |
199 static ObjcType!(R) forwardStaticCall (id self, SEL cmd, ObjcArgs objcArgs) | 445 * objcArgs = the encapsulated arguments to the binded method |
446 * | |
447 * Returns: whatever the binded method returns, encapsulated | |
448 */ | |
449 extern (C) static dstep.objc.bridge.Type.ObjcType!(R) __forwardStaticCall (dstep.objc.objc.Class self, dstep.objc.objc.SEL cmd, __ObjcArgs objcArgs) | |
200 in | 450 in |
201 { | 451 { |
202 assert(isCapsule(self)); | 452 assert(dstep.objc.bridge.Capsule.isCapsule(self)); |
203 } | 453 } |
204 body | 454 body |
205 { | 455 { |
206 R function (ARGS) dg = &method; | 456 R function (ARGS) funcPtr = &method; |
207 | |
208 ARGS args; | 457 ARGS args; |
209 | 458 |
210 foreach (i, a ; objcArgs) | 459 foreach (i, a ; objcArgs) |
211 { | 460 { |
212 alias typeof(args[i]) ArgType; | 461 alias typeof(args[i]) ArgType; |
213 | 462 args[i] = dstep.objc.bridge.Capsule.decapsule!(ArgType)(a); |
214 args[i] = decapsule!(ArgType)(a); | |
215 } | 463 } |
216 | 464 |
217 static if (needsEncapsulation!(R)) | 465 static if (is(R == void)) |
218 return encapsule!(R)(dg(args)); | 466 funcPtr()(args); |
219 | 467 |
220 else | 468 else |
221 return dg(args); | 469 return dstep.objc.bridge.Capsule.encapsule!(R)(funcPtr()(args)); |
222 } | 470 } |
223 } | 471 |
224 } | 472 /// The Objective-C method declaration for the binded method |
225 | 473 ObjcMethodDeclaration!(__forwardStaticCall, R, selector, ARGS) __objcClassMethodDeclaration; |
474 } | |
475 } | |
476 | |
477 /** | |
478 * Binds a D free function to an Objective-C free function. | |
479 * | |
480 * This will create a receiver function which will forward the call to the | |
481 * binded function, decapsulating arguments and encapsulating the return value | |
482 * as appropriate. | |
483 * | |
484 * Mixes in: $(D_PSYMBOL ObjcBindFunction) | |
485 * | |
486 * Examples: | |
487 * --- | |
488 * void foo (); | |
489 * mixin ObjcBindFunction!(foo); | |
490 * --- | |
491 */ | |
226 template ObjcBindFunction (alias func) | 492 template ObjcBindFunction (alias func) |
227 { | 493 { |
228 mixin ObjcBindFunction!(func, ReturnTypeOf!(func), ParameterTupleOf!(func)); | 494 mixin ObjcBindFunction!(func, ReturnTypeOf!(func), ParameterTupleOf!(func)); |
229 } | 495 } |
230 | 496 |
497 /** | |
498 * Binds a D free function to an Objective-C free function. | |
499 * | |
500 * This will create a receiver function which will forward the call to the | |
501 * binded function, decapsulating arguments and encapsulating the return value | |
502 * as appropriate. | |
503 * | |
504 * Examples: | |
505 * --- | |
506 * char foo (int); | |
507 * mixin ObjcBindFunction!(foo, char, int); | |
508 * --- | |
509 * | |
510 * Params: | |
511 * func = the function to bind | |
512 * R = the return type of the function | |
513 * ARGS = the argument types of the function | |
514 */ | |
231 template ObjcBindFunction (alias func, R, ARGS...) | 515 template ObjcBindFunction (alias func, R, ARGS...) |
232 { | 516 { |
233 private | 517 private |
234 { | 518 { |
235 import dstep.objc.bridge.Capsule : decapsule, encapsule, needsEncapsulation, ObjcType; | 519 /// A type tuple with all the encapsulated types |
236 import dstep.internal.Tuple; | 520 alias dstep.objc.bridge.Type.ObjcTypes!(ARGS) __ObjcArgs; |
237 | 521 |
238 ObjcMethodDeclaration!(method, R, selector, ARGS) objcClassMethodDeclaration; | 522 /** |
239 | 523 * The receiver function, this will be the function called from the Objective-C side |
240 alias ReplaceAllClasses!(id, ARGS) ObjcArgs; | 524 * |
241 | 525 * Params: |
242 extern (C) ObjcType!(R) forwardFunctionCall (ObjcArgs objcArgs) | 526 * objcArgs = the encapsulated arguments to the binded function |
527 * | |
528 * Returns: whatever the binded function returns, encapsulated | |
529 */ | |
530 extern (C) dstep.internal.Types.ObjcType!(R) __forwardFunctionCall (__ObjcArgs objcArgs) | |
243 { | 531 { |
532 R function (ARGS) funcPtr = &func; | |
244 ARGS args; | 533 ARGS args; |
245 | 534 |
246 foreach (i, a ; objcArgs) | 535 foreach (i, a ; objcArgs) |
247 { | 536 { |
248 alias typeof(args[i]) ArgType; | 537 alias typeof(args[i]) ArgType; |
249 | 538 args[i] = dstep.objc.bridge.Capsule.decapsule!(ArgType)(a); |
250 args[i] = decapsule!(ArgType)(a); | |
251 } | 539 } |
252 | 540 |
253 static if (needsEncapsulation!(R)) | 541 static if (is(R == void)) |
254 return encapsule!(R)(dg(args)); | 542 funcPtr()(args); |
255 | 543 |
256 else | 544 else |
257 return dg(args); | 545 return dstep.objc.bridge.Capsule.encapsule!(R)(funcPtr()(args)); |
258 } | 546 } |
259 } | 547 } |
260 } | 548 } |
261 | 549 |
262 struct Bridge | 550 /// This $(D_KEYWORD class) acts like a name space for various methods and functions |
551 class Bridge | |
263 { | 552 { |
553 private static Bridge bridgeInstance; | |
554 | |
555 /// The name of the method declaration variable mixed in in a $(D_KEYWORD class) | |
556 const objcMethodDeclarationVar = "__objcMethodDeclaration"; | |
557 | |
558 /// The name of the class method declaration variable mixed in in a $(D_KEYWORD class) | |
559 const objcClassMethodDeclarationVar = "__objcClassMethodDeclaration"; | |
560 | |
561 /// The name of the variable used on the Objective-C side to store the D object | |
562 const dObjectVar = "dObject"; | |
563 | |
564 /// This alias is used as an internal representation of a D object | |
565 //alias Object DObjectType; | |
566 alias void* DObjectType; | |
567 | |
568 /** | |
569 * Gets the only instance of this class | |
570 * | |
571 * Returns: the instance | |
572 */ | |
573 static Bridge instance () | |
574 { | |
575 if (bridgeInstance) | |
576 return bridgeInstance; | |
577 | |
578 return bridgeInstance = new Bridge; | |
579 } | |
580 | |
264 static: | 581 static: |
265 | 582 |
266 const objcMethodDeclarationVar = "objcMethodDeclaration"; | 583 /** |
267 const objcClassMethodDeclarationVar = "objcClassMethodDeclaration"; | 584 * Gets the value of an Objective-C instance variable |
268 const dObjectVar = "dObject"; | 585 * |
269 alias void* DObjectType; | 586 * Examples: |
270 private ClassInfo[string] registeredClasses; | 587 * --- |
271 | 588 * id self; |
272 void registerClass (string className, ClassInfo classInfo) | 589 * int x = getObjcIvar!(int, "x")(self); |
273 { | 590 * --- |
274 if (className.length > 2 && className[0 .. 2] == "D_") | 591 * |
275 registeredClasses[className[0 .. 2]] = classInfo; | 592 * Params: |
276 | 593 * T = the type of the instance variable |
277 else | 594 * name = the name of the instance variable |
278 registeredClasses[className] = classInfo; | 595 * self = the Objective-C instance |
279 } | 596 * |
280 | 597 * Returns: the value of the Objective-C variable |
281 Object createRegisteredObject (T) (string className) | 598 */ |
282 { | 599 T getObjcIvar (T, string name) (id self) |
283 return null; | 600 { |
284 } | 601 T value; |
285 | 602 |
286 DObjectType getDObject (id self) | 603 self.getInstanceVariable!(T, name)(value); |
287 { | 604 |
288 DObjectType dObject; | 605 return value; |
289 | 606 } |
290 self.getInstanceVariable!(DObjectType, dObjectVar)(dObject); | 607 |
291 | 608 /** |
292 return dObject; | 609 * Sets the value of an Objective-C instance variable |
293 } | 610 * |
294 | 611 * Examples: |
295 id setDObject (Object dObject, id objcObject) | 612 * --- |
296 { | 613 * id self; |
297 auto o = cast(DObjectType) dObject; | 614 * Bridge.setObjcIvar!(int, "x")(self, 3); |
298 addRoot(o); | 615 * --- |
299 | 616 * |
300 objcObject.setInstanceVariable!(DObjectType, Bridge.dObjectVar)(o); | 617 * Params: |
618 * T = the type of the instance variable | |
619 * name = the name of the instance | |
620 * objcObject = the Objective-C instance | |
621 * value = the value to set | |
622 */ | |
623 void setObjcIvar (T, string name) (id self, T value) | |
624 { | |
625 GC.addRoot(value); | |
626 self.setInstanceVariable!(T, dObjectVar)(value); | |
627 } | |
628 | |
629 /** | |
630 * Gets the D object stored in the given Objective-C instance | |
631 * | |
632 * Examples: | |
633 * --- | |
634 * NSObject object = new NSObject; | |
635 * id self = object.objcObject; | |
636 * assert(object == Bridge.getDObject(self)); | |
637 * --- | |
638 * | |
639 * Params: | |
640 * self = the Objective-C instance | |
641 * | |
642 * Returns: the D object or null | |
643 */ | |
644 package DObjectType getDObject (id self) | |
645 { | |
646 return getObjcIvar!(DObjectType, dObjectVar)(self); | |
647 } | |
648 | |
649 /** | |
650 * Stores the given D object in the given Objective-C instance | |
651 * | |
652 * Examples: | |
653 * --- | |
654 * NSObject object = new NSObject; | |
655 * id self = object.objcObject; | |
656 * Bridge.setDObject(object, self); | |
657 * --- | |
658 * | |
659 * Params: | |
660 * dObject = the D object to store | |
661 * objcObject = the Objective-C instance to store the D object in | |
662 * | |
663 * Returns: the Objective-C instance | |
664 */ | |
665 package id setDObject (Object dObject, id objcObject) | |
666 { | |
667 auto o = cast(DObjectType) dObject; | |
668 setObjcIvar!(DObjectType, dObjectVar)(objcObject, o); | |
301 | 669 |
302 return objcObject; | 670 return objcObject; |
303 } | 671 } |
304 | 672 |
673 /** | |
674 * Deregisters the given Objective-C instance from the bridge | |
675 * | |
676 * Params: | |
677 * objcInstance = the Objective-C instance to deregister | |
678 */ | |
679 package static void deregisterObjcInstance (id objcInstance) | |
680 { | |
681 GC.removeRoot(getObjcIvar!(DObjectType, dObjectVar)(objcInstance)); | |
682 } | |
683 | |
684 /** | |
685 * This method wraps the family of $(D_PSYMBOL objc_msgSend) methods which is used to send a message | |
686 * to an instance of a class. | |
687 * | |
688 * This method chooses the appropriate $(D_PSYMBOL objc_msgSend) method depending on the return value, | |
689 * decapsulating arguments and encapsulating the return value as appropriate. | |
690 * | |
691 * Params: | |
692 * R = the return type | |
693 * selector = the selector to call | |
694 * ARGS = the argument types | |
695 * self = the reciver of the call | |
696 * args = the arguments to the method | |
697 * | |
698 * Returns: whatever the method returns, encapsulaed | |
699 */ | |
305 R invokeObjcMethod (R, string selector, ARGS...) (id self, ARGS args) | 700 R invokeObjcMethod (R, string selector, ARGS...) (id self, ARGS args) |
306 { | 701 { |
307 static if (!is(R : void)) | 702 static assert (checkSelector!(selector, ARGS), "The selector \"" ~ selector ~ "\" and the arguments " ~ ARGS.stringof ~ " do not match"); |
308 R result; | |
309 | 703 |
310 SEL sel = sel.registerName!(selector); | 704 SEL sel = sel.registerName!(selector); |
311 | 705 ObjcTypes!(ARGS) objcArgs; |
312 alias ReplaceAllClasses!(id, ARGS) ObjcArgs; | |
313 ObjcArgs objcArgs; | |
314 | 706 |
315 foreach (i, a ; args) | 707 foreach (i, a ; args) |
316 { | 708 { |
317 alias typeof(a) ArgType; | 709 alias typeof(a) ArgType; |
318 | 710 |
319 objcArgs[i] = encapsule!(ArgType)(a); | 711 objcArgs[i] = encapsule!(ArgType)(a); |
320 } | 712 } |
321 | 713 |
322 static if (is(R == struct)) | 714 static if (is(R == struct)) |
323 { | 715 { |
716 R result; | |
324 self.msgSend_stret(result, sel, objcArgs); | 717 self.msgSend_stret(result, sel, objcArgs); |
718 | |
325 return result; | 719 return result; |
326 } | 720 } |
327 | 721 |
328 else static if (is(R == float) || is(R == double) || is(R == real)) | 722 else static if (is(R == float) || is(R == double) || is(R == real)) |
329 { | 723 { |
330 version (X86) | 724 version (X86) |
331 { | 725 return self.msgSend_fpret!(R, ObjcTypes!(ARGS))(sel, objcArgs); |
332 static if (is(R == float)) | |
333 return self.msgSend_fpret!(R)(sel, objcArgs); | |
334 | |
335 else | |
336 return self.msgSend_fpret(sel, objcArgs); | |
337 } | |
338 | 726 |
339 else version (X86_64) | 727 else version (X86_64) |
340 { | 728 { |
341 static if (is(R == real)) | 729 static if (is(R == real)) |
342 return self.msgSend_fpret(sel, objcArgs); | 730 return self.msgSend_fpret!(R)(sel, objcArgs); |
343 | 731 |
344 else | 732 else |
345 return self.msgSend!(R)(sel, objcArgs); | 733 return self.msgSend!(R)(sel, objcArgs); |
346 } | 734 } |
347 | 735 |
348 else | 736 else |
349 return self.msgSend!(R)(sel, objcArgs); | 737 return self.msgSend!(R)(sel, objcArgs); |
350 } | 738 } |
351 | 739 |
352 else static if (is(R : ObjcWrapper)) | 740 else static if (needsEncapsulation!(R)) |
353 { | 741 return decapsule!(R)(self.msgSend(sel, objcArgs)); |
354 id r = self.msgSend(sel, objcArgs); | |
355 | |
356 if (!r) | |
357 return null; | |
358 | |
359 if (isCapsule(r)) | |
360 { | |
361 result = decapsule!(R)(r); | |
362 | |
363 if (result) | |
364 return result; | |
365 } | |
366 | |
367 return new R(r); | |
368 } | |
369 | |
370 else static if (is(R : Object)) | |
371 { | |
372 id r = self.msgSend(sel, objcArgs); | |
373 | |
374 if (!r) | |
375 return null; | |
376 | |
377 return decapsule!(R)(r); | |
378 } | |
379 | 742 |
380 else | 743 else |
381 return self.msgSend!(R, ObjcArgs)(sel, objcArgs); | 744 return self.msgSend!(R, ObjcTypes!(ARGS))(sel, objcArgs); |
382 } | 745 } |
383 | 746 |
384 R invokeObjcClassMethod (R = id, string selector, ARGS...) (Class cls, ARGS args) | 747 /** |
748 * This method wraps the family of $(D_PSYMBOL objc_msgSend) methods which is used to send a message | |
749 * to a class. | |
750 * | |
751 * This method chooses the appropriate $(D_PSYMBOL objc_msgSend) method depending on the return value, | |
752 * decapsulating arguments and encapsulating the return value as appropriate. | |
753 * | |
754 * Params: | |
755 * R = the return type | |
756 * selector = the selector to call | |
757 * ARGS = the argument types | |
758 * cls = the reciver of the call | |
759 * args = the arguments to the method | |
760 * | |
761 * Returns: whatever the method returns, encapsulaed | |
762 */ | |
763 R invokeObjcClassMethod (R, string selector, ARGS...) (Class cls, ARGS args) | |
385 { | 764 { |
386 return invokeObjcMethod!(R, selector, ARGS)(cast(id) cls, args); | 765 return invokeObjcMethod!(R, selector, ARGS)(cast(id) cls, args); |
387 } | 766 } |
388 | 767 |
389 R invokeObjcSuperMethod (R = id, string selector, ARGS...) (objc_super* self, ARGS args) | 768 /** |
390 { | 769 * This method wraps the family of $(D_PSYMBOL objc_msgSendSuper) methods which is used to send a message |
391 R result; | 770 * to an instance of a superclass. |
771 * | |
772 * This method chooses the appropriate $(D_PSYMBOL objc_msgSendSuper) method depending on the return value, | |
773 * decapsulating arguments and encapsulating the return value as appropriate. | |
774 * | |
775 * Params: | |
776 * R = the return type | |
777 * selector = the selector to call | |
778 * ARGS = the argument types | |
779 * self = the reciver of the call | |
780 * args = the arguments to the method | |
781 * | |
782 * Returns: whatever the method returns, encapsulaed | |
783 */ | |
784 R invokeObjcSuperMethod (R, string selector, ARGS...) (objc_super* self, ARGS args) | |
785 { | |
786 static assert (checkSelector!(selector, ARGS), "The selector \"" ~ selector ~ "\" and the arguments " ~ ARGS.stringof ~ " do not match"); | |
787 | |
392 SEL sel = sel.registerName!(selector); | 788 SEL sel = sel.registerName!(selector); |
393 | 789 ObjcTypes!(ARGS) objcArgs; |
394 alias ReplaceAllClasses!(id, ARGS) ObjcArgs; | |
395 ObjcArgs objcArgs; | |
396 | 790 |
397 foreach (i, a ; args) | 791 foreach (i, a ; args) |
398 { | 792 { |
399 alias typeof(a) ArgType; | 793 alias typeof(a) ArgType; |
400 | 794 |
401 objcArgs[i] = encapsule!(ArgType)(a); | 795 objcArgs[i] = encapsule!(ArgType)(a); |
402 } | 796 } |
403 | 797 |
404 static if (is(R == struct)) | 798 static if (is(R == struct)) |
405 { | 799 { |
800 R result; | |
406 self.msgSendSuper_stret(result, sel, objcArgs); | 801 self.msgSendSuper_stret(result, sel, objcArgs); |
407 } | 802 |
408 | 803 return result; |
409 else static if (is(R : ObjcWrapper)) | 804 } |
410 { | 805 |
411 id r = self.msgSendSuper(sel, objcArgs); | 806 else static if (needsEncapsulation!(R)) |
412 | 807 return decapsule!(R)(self.msgSendSuper(sel, objcArgs)); |
413 if (isCapsule(r)) | |
414 { | |
415 result = decapsule!(R)(r); | |
416 | |
417 if (result) | |
418 return result; | |
419 } | |
420 | |
421 return r ? new R(r) : null; | |
422 } | |
423 | |
424 else static if (is(R : Object)) | |
425 { | |
426 id r = self.msgSendSuper(sel, objcArgs); | |
427 return decapsule!(R)(r); | |
428 } | |
429 | 808 |
430 else | 809 else |
431 return self.msgSend!(R)(sel, objcArgs); | 810 return self.msgSendSuper!(R, ObjcTypes!(ARGS))(sel, objcArgs); |
432 } | 811 } |
433 | 812 |
813 /** | |
814 * This method wraps a call to a regular C free function, decapsulating arguments and | |
815 * encapsulating the return value as appropriate. | |
816 * | |
817 * Params: | |
818 * R = the return type | |
819 * func = the function to call | |
820 * ARGS = the argument types | |
821 * args = the arguments to the function | |
822 * | |
823 * Returns: whatever the method returns, encapsulaed | |
824 */ | |
434 R invokeObjcFunction (R, alias func, ARGS...) (ARGS args) | 825 R invokeObjcFunction (R, alias func, ARGS...) (ARGS args) |
435 { | 826 { |
436 static if (!is(R : void)) | 827 auto funcPtr = &func; // use a function pointer instead of the alias because the function may not be public. |
437 R result; | 828 ObjcTypes!(ARGS) objcArgs; |
438 | |
439 auto funcPtr = &func; // use a function pointer instead of the alias because the function can be private. | |
440 | |
441 alias ReplaceAllClasses!(id, ARGS) ObjcArgs; | |
442 ObjcArgs objcArgs; | |
443 | 829 |
444 foreach (i, a ; args) | 830 foreach (i, a ; args) |
445 { | 831 { |
446 alias typeof(a) ArgType; | 832 alias typeof(a) ArgType; |
447 | 833 |
448 objcArgs[i] = encapsule!(ArgType)(a); | 834 objcArgs[i] = encapsule!(ArgType)(a); |
449 } | 835 } |
450 | 836 |
451 static if (is(R : ObjcWrapper)) | 837 static if (is(R == void)) |
452 { | 838 funcPtr(objcArgs); |
453 id r = funcPtr(objcArgs); | |
454 | |
455 if (!r) | |
456 return null; | |
457 | |
458 if (isCapsule(r)) | |
459 { | |
460 result = decapsule!(R)(r); | |
461 | |
462 if (result) | |
463 return result; | |
464 } | |
465 | |
466 return new R(r); | |
467 } | |
468 | |
469 else static if (is(R : Object)) | |
470 { | |
471 id r = funcPtr(objcArgs); | |
472 | |
473 if (!r) | |
474 return null; | |
475 | |
476 return decapsule!(R)(r); | |
477 } | |
478 | 839 |
479 else | 840 else |
480 return funcPtr(objcArgs); | 841 return decapsule!(R)(funcPtr(objcArgs)); |
481 } | 842 } |
482 } | 843 } |