Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

root/dstep/objc/bridge/ClassInitializer.d

Revision 16:19885b43130e, 7.7 kB (checked in by Jacob Carlborg <doob@me.com>, 15 years ago)

Huge update, the bridge actually works now

  • Property exe set to *
Line 
1 /**
2  * Copyright: Copyright (c) 2009 Jacob Carlborg.
3  * Authors: Jacob Carlborg
4  * Version: Initial created: Apr 7, 2009
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module dstep.objc.bridge.ClassInitializer;
8
9 version (Tango)
10     import tango.math.Math;
11
12 else
13     import std.math;
14
15 import dstep.internal.String;
16 import dstep.internal.Traits;
17 import bindings = dstep.objc.bindings;
18 import dstep.objc.bridge.Bridge;
19 import dstep.objc.bridge.TypeEncoding;
20 import dstep.objc.objc;
21 import dstep.objc.runtime;
22
23 /**
24  * Objective-C subclass initializer template.
25  *
26  * Param:
27  *     subclassName = the name of the subclass to create
28  *     superClassName = the name of the Objective-C superclass
29  */
30 package template ObjcSubclassInitializer (string subclassName, string superclassName)
31 {
32     /**
33      * Return a pointer to the created class data structure. If this class hasn't been added
34      * to the Objective-C runtime, it'll be added.
35      * 
36      * Returns: a pointer to the created class data structure
37      */
38     static dstep.objc.objc.Class objcClass ()
39     {       
40         if (__objcClass)
41             return __objcClass;
42        
43         dstep.objc.objc.Class superClass = objcSuperClass;
44        
45         auto methods = __collectObjcInstanceMethods();
46         auto classMethods = __collectObjcClassMethods();
47        
48         static if (dstep.internal.Traits.hasClassMethod!(typeof(super), objcClass.stringof))
49             typeof(super).objcClass;
50        
51         return __objcClass = dstep.objc.bridge.ClassInitializer.subclassInit!(subclassName)(superClass, methods, classMethods);
52     }
53    
54     /**
55      * Return a pointer to the superclass data structure. If the superclass hasn't been added
56      * to the Objective-C runtime, it'll be added.
57      *
58      * Returns: a pointer to the superclass data structure
59      */
60     static dstep.objc.objc.Class objcSuperClass ()
61     {
62         if (__objcSuperClass)
63             return __objcSuperClass;
64        
65         if (is(typeof(super) == dstep.objc.bridge.Wrapper.ObjcWrapper)) // root class
66             return __objcSuperClass = dstep.objc.bridge.Capsule.capsuleClass;
67        
68         __objcSuperClass = cast(dstep.objc.objc.Class) dstep.objc.objc.objc.getClass!(subclassName);
69        
70         while (!__objcSuperClass && !is(typeof(super) == dstep.objc.bridge.Wrapper.ObjcWrapper))
71             __objcSuperClass = super.objcClass;
72        
73         if (!__objcSuperClass)
74             __objcSuperClass = dstep.objc.bridge.Capsule.capsuleClass;
75        
76         return __objcSuperClass;
77     }
78    
79     /**
80      * Collects all binded methods in the class this template is mixed into.
81      *
82      * Returns: an array of methods
83      */
84     private static dstep.objc.runtime.Method[] __collectObjcInstanceMethods ()
85     {
86         dstep.objc.runtime.Method[] methods;
87        
88         mixin("alias " ~ subclassName ~ " Type;");
89                
90         static if (Type.tupleof.length > 0)
91         {
92             foreach (i, f ; typeof(Type.tupleof))
93             {
94                 const len = Type.stringof.length;
95                 const fieldName = Type.tupleof[i].stringof[1 + len + 2 .. $];           
96                
97                 static if (fieldName == dstep.objc.bridge.Bridge.Bridge.objcMethodDeclarationVar)
98                 {               
99                     typeof(Type.tupleof[i]) field;
100
101                     dstep.objc.runtime.Method m = new dstep.objc.objc.objc_method;
102                     m.method_name = dstep.objc.objc.sel.registerName!(field.methodName);
103                     m.method_types = dstep.objc.bridge.TypeEncoding.encode!(field.returnType, dstep.objc.objc.id, dstep.objc.objc.SEL, field.argsType).ptr;
104                     m.method_imp = cast(dstep.objc.objc.IMP) field.methodImp;
105                    
106                     methods ~= m;
107                 }
108             }
109         }
110        
111         return methods;
112     }
113    
114     /**
115      * Collects all binded class methods in the class this template is mixed into.
116      *
117      * Returns:
118      */
119     private static dstep.objc.runtime.Method[] __collectObjcClassMethods ()
120     {
121         dstep.objc.runtime.Method[] methods;
122        
123         mixin("alias " ~ subclassName ~ " Type;");
124        
125         static if (Type.tupleof.length > 0)
126         {
127             foreach (i, f ; typeof(Type.tupleof))
128             {
129                 const len = Type.stringof.length;
130                 const fieldName = Type.tupleof[i].stringof[1 + len + 2 .. $];
131                
132                 static if (fieldName == dstep.objc.bridge.Bridge.Bridge.objcClassMethodDeclarationVar)
133                 {               
134                     typeof(Type.tupleof[i]) field;
135
136                     dstep.objc.runtime.Method m = new dstep.objc.objc.objc_method;
137                     m.method_name = dstep.objc.objc.sel.registerName!(field.methodName);
138                     m.method_types = dstep.objc.bridge.TypeEncoding.encode!(field.returnType, field.argsType).ptr;
139                     m.method_imp = cast(dstep.objc.objc.IMP) field.methodImp;
140
141                     methods ~= m;
142                 }
143             }
144         }
145        
146         return methods;
147     }
148    
149     /**
150      * Invoke on the receiver the instance method with the given name, return type
151      * and arguments.     
152      *
153      * Params:
154      *     R = the return type
155      *     name = the name (selector) of the method to invoke
156      *     ARGS = the type of the arguments
157      *     args = the arguments to the method
158      *     
159      * Returns: whatever the method returns
160      */
161     private R invokeObjcSelf (R, dstep.internal.String.string name, ARGS...) (ARGS args)
162     {
163         return dstep.objc.bridge.Bridge.Bridge.invokeObjcMethod!(R, name, ARGS)(this.objcObject, args);
164     }
165    
166     /**
167      * Invoke on the receiver's super part the instance method with the given name,
168      * return type and arguments.     
169      *
170      * Params:
171      *     R = the return type
172      *     name = the name (selector) of the method to invoke
173      *     ARGS = the type of the arguments
174      *     args = the arguments to the method
175      *     
176      * Returns: whatever the method returns
177      */
178     private R invokeObjcSuper (R, dstep.internal.String.string name, ARGS...) (ARGS args)
179     {
180         return dstep.objc.bridge.Bridge.Bridge.invokeObjcSuperMethod!(R, name, ARGS)(this.objcSuper, args);
181     }
182    
183     /**
184      * Invoke class method with given name, return type and arguments,
185      * on the receiver's superclass.     
186      *
187      * Params:
188      *     R = the return type
189      *     name = the name (selector) of the method to invoke
190      *     ARGS = the type of the arguments
191      *     args = the arguments to the method
192      *     
193      * Returns: whatever the method returns
194      */
195     private static R invokeObjcSelfClass (R, dstep.internal.String.string name, ARGS...) (ARGS args)
196     {
197         return dstep.objc.bridge.Bridge.Bridge.invokeObjcClassMethod!(R, name, ARGS)(objcClass, args);
198     }
199    
200     /**
201      * Invoke class method with given name, return type and arguments,
202      * on the receiver's superclass.     
203      *
204      * Params:
205      *     R = the return type
206      *     name = the name (selector) of the method to invoke
207      *     ARGS = the type of the arguments
208      *     args = the arguments to the method
209      *     
210      * Returns: whatever the method returns
211      */
212     private static R invokeObjcSuperClass (R, dstep.internal.String.string name, ARGS...) (ARGS args)
213     {       
214         return dstep.objc.bridge.Bridge.Bridge.invokeObjcClassMethod!(R, name, ARGS)(objcSuperClass, args);
215     }
216 }
217
218 /**
219  * Creates a new Objective-C subclass, initializes its data and register it with the
220  * Objective-C runtime.
221  *
222  * Params:
223  *     className = the name of the subclass
224  *     superClass = the subclass' superclass
225  *     instanceMethods = the instance methods that should be added to the subclass
226  *     classMethods = the class methods that should be added to the subclass
227  *     
228  * Returns: the newly created subclass
229  */
230 Class subclassInit (string className) (Class superClass, Method[] instanceMethods = null, Method[] classMethods = null)
231 {
232     Class cls;
233    
234     if (objc.getClass!(className))
235         cls = objc.allocateClassPair!("D_" ~ className)(superClass, 0);
236    
237     else
238         cls = objc.allocateClassPair!(className)(superClass, 0);
239    
240     Class metaClass = (cast(id) cls).getClass;
241    
242     ubyte alignment = cast(ubyte) log2(Bridge.DObjectType.sizeof);
243     cls.addIvar!(Bridge.dObjectVar, encode!(Bridge.DObjectType))(Bridge.DObjectType.sizeof, alignment);
244    
245     foreach (method ; instanceMethods)
246         bindings.class_addMethod(cls, method.method_name, method.method_imp, method.method_types);
247    
248     foreach (method ; classMethods)
249         bindings.class_addMethod(metaClass, method.method_name, method.method_imp, method.method_types);
250    
251     objc.registerClassPair(cls);
252    
253     return cls;
254 }
Note: See TracBrowser for help on using the browser.