root/dstep/objc/bridge/Bridge.d

Revision 27:57371c29ef73, 23.9 kB (checked in by Jacob Carlborg <doob@me.com>, 4 years ago)

ObjcWrap? is now automatically mixed in. Added support for building as a dylib with DMD.

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