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 }