Mercurial > projects > dstep
comparison dstep/objc/bridge/ClassInitializer.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 | 9fd439a28ce3 |
children |
comparison
equal
deleted
inserted
replaced
15:7ff919f595d5 | 16:19885b43130e |
---|---|
11 | 11 |
12 else | 12 else |
13 import std.math; | 13 import std.math; |
14 | 14 |
15 import dstep.internal.String; | 15 import dstep.internal.String; |
16 import dstep.internal.Traits; | |
16 import bindings = dstep.objc.bindings; | 17 import bindings = dstep.objc.bindings; |
17 import dstep.objc.bridge.Bridge; | 18 import dstep.objc.bridge.Bridge; |
18 import dstep.objc.bridge.TypeEncoding; | 19 import dstep.objc.bridge.TypeEncoding; |
19 import dstep.objc.objc; | 20 import dstep.objc.objc; |
20 import dstep.objc.runtime; | 21 import dstep.objc.runtime; |
21 | 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 */ | |
22 package template ObjcSubclassInitializer (string subclassName, string superclassName) | 30 package template ObjcSubclassInitializer (string subclassName, string superclassName) |
23 { | 31 { |
24 import dstep.internal.String : string; | 32 /** |
25 import dstep.objc.bridge.Bridge : ObjcBindMethod; | 33 * Return a pointer to the created class data structure. If this class hasn't been added |
26 import dstep.objc.runtime : Method, objc_method, sel, objc; | 34 * to the Objective-C runtime, it'll be added. |
27 import dstep.objc.bridge.TypeEncoding : encode; | 35 * |
28 | 36 * Returns: a pointer to the created class data structure |
29 static Class objcClass () | 37 */ |
38 static dstep.objc.objc.Class objcClass () | |
30 { | 39 { |
31 if (objcClass_) | 40 if (__objcClass) |
32 return objcClass_; | 41 return __objcClass; |
33 | 42 |
34 Class superClass = cast(Class) objc.getClass!(superclassName); | 43 dstep.objc.objc.Class superClass = objcSuperClass; |
35 | 44 |
36 while (!superClass) | 45 auto methods = __collectObjcInstanceMethods(); |
37 superClass = super.objcClass; | 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;"); | |
38 | 89 |
39 return objcClass_ = subclassInit!(subclassName)(superClass, collectObjcInstanceMethods, collectObjcClassMethods); | 90 static if (Type.tupleof.length > 0) |
40 } | |
41 | |
42 private static Method[] collectObjcInstanceMethods () | |
43 { | |
44 Method[] methods; | |
45 | |
46 mixin("alias " ~ superclassName ~ " Type;"); | |
47 | |
48 foreach (i, f; typeof(Type.tupleof)) | |
49 { | 91 { |
50 const len = Type.stringof.length; | 92 foreach (i, f ; typeof(Type.tupleof)) |
51 const fieldName = Type.tupleof[i].stringof[1 + len + 2 .. $]; | |
52 | |
53 static if (fieldName == Bridge.objcMethodDeclarationVar) | |
54 { | 93 { |
55 typeof(Type.tupleof[i]) field; | 94 const len = Type.stringof.length; |
56 | 95 const fieldName = Type.tupleof[i].stringof[1 + len + 2 .. $]; |
57 Method m = new objc_method; | |
58 m.method_name = sel.registerName!(field.methodName); | |
59 m.method_types = encode!(field.returnType, id, SEL, field.argsType).ptr; | |
60 m.method_imp = cast(IMP) &Type.ObjcBindMethod!(field.methodImp, field.returnType, field.methodName, field.argsType).forwardVirtualCall; | |
61 | 96 |
62 methods ~= m; | 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 } | |
63 } | 108 } |
64 } | 109 } |
65 | 110 |
66 return methods; | 111 return methods; |
67 } | 112 } |
68 | 113 |
69 private static Method[] collectObjcClassMethods () | 114 /** |
70 { | 115 * Collects all binded class methods in the class this template is mixed into. |
71 Method[] methods; | 116 * |
72 | 117 * Returns: |
73 mixin("alias " ~ superclassName ~ " Type;"); | 118 */ |
74 | 119 private static dstep.objc.runtime.Method[] __collectObjcClassMethods () |
75 foreach (i, f; typeof(Type.tupleof)) | 120 { |
121 dstep.objc.runtime.Method[] methods; | |
122 | |
123 mixin("alias " ~ subclassName ~ " Type;"); | |
124 | |
125 static if (Type.tupleof.length > 0) | |
76 { | 126 { |
77 const len = Type.stringof.length; | 127 foreach (i, f ; typeof(Type.tupleof)) |
78 const fieldName = Type.tupleof[i].stringof[1 + len + 2 .. $]; | |
79 | |
80 static if (fieldName == Bridge.objcClassMethodDeclarationVar) | |
81 { | 128 { |
82 typeof(Type.tupleof[i]) field; | 129 const len = Type.stringof.length; |
83 | 130 const fieldName = Type.tupleof[i].stringof[1 + len + 2 .. $]; |
84 Method m = new objc_method; | |
85 m.method_name = sel.registerName!(field.methodName); | |
86 m.method_types = encode!(field.returnType, field.argsType).ptr; | |
87 m.method_imp = cast(IMP) &Type.ObjcBindClassMethod!(field.methodImp, field.returnType, field.methodName, field.argsType).forwardStaticCall; | |
88 | 131 |
89 methods ~= m; | 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 } | |
90 } | 143 } |
91 } | 144 } |
92 | 145 |
93 return methods; | 146 return methods; |
94 } | 147 } |
95 | 148 |
96 private R invokeObjcSelf (R, string name, ARGS...) (ARGS args) | 149 /** |
97 { | 150 * Invoke on the receiver the instance method with the given name, return type |
98 return Bridge.invokeObjcMethod!(R, name, ARGS)(objcObject, args); | 151 * and arguments. |
99 } | 152 * |
100 | 153 * Params: |
101 private R invokeObjcSuper (R, string name, ARGS...) (ARGS args) | 154 * R = the return type |
102 { | 155 * name = the name (selector) of the method to invoke |
103 return Bridge.invokeObjcMethod!(R, name, ARGS)(objcSuper, args); | 156 * ARGS = the type of the arguments |
104 } | 157 * args = the arguments to the method |
105 | 158 * |
106 private static R invokeObjcSelfClass (R, string name, ARGS...) (ARGS args) | 159 * Returns: whatever the method returns |
107 { | 160 */ |
108 return Bridge.invokeObjcClassMethod!(R, name, ARGS)(objcClass, args); | 161 private R invokeObjcSelf (R, dstep.internal.String.string name, ARGS...) (ARGS args) |
109 } | 162 { |
110 | 163 return dstep.objc.bridge.Bridge.Bridge.invokeObjcMethod!(R, name, ARGS)(this.objcObject, args); |
111 private static R invokeObjcSuperClass (R, string name, ARGS...) (ARGS args) | 164 } |
112 { | 165 |
113 return Bridge.invokeObjcClassMethod!(R, name, ARGS)(objcSuperClass, args); | 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); | |
114 } | 215 } |
115 } | 216 } |
116 | 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 */ | |
117 Class subclassInit (string className) (Class superClass, Method[] instanceMethods = null, Method[] classMethods = null) | 230 Class subclassInit (string className) (Class superClass, Method[] instanceMethods = null, Method[] classMethods = null) |
118 { | 231 { |
119 Class cls = objc.allocateClassPair!(className)(superClass, 0); | 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 | |
120 Class metaClass = (cast(id) cls).getClass; | 240 Class metaClass = (cast(id) cls).getClass; |
121 | 241 |
122 ubyte alignment = cast(ubyte) log2(Bridge.DObjectType.sizeof); | 242 ubyte alignment = cast(ubyte) log2(Bridge.DObjectType.sizeof); |
123 | |
124 cls.addIvar!(Bridge.dObjectVar, encode!(Bridge.DObjectType))(Bridge.DObjectType.sizeof, alignment); | 243 cls.addIvar!(Bridge.dObjectVar, encode!(Bridge.DObjectType))(Bridge.DObjectType.sizeof, alignment); |
125 | 244 |
126 foreach (method ; instanceMethods) | 245 foreach (method ; instanceMethods) |
127 bindings.class_addMethod(cls, method.method_name, method.method_imp, method.method_types); | 246 bindings.class_addMethod(cls, method.method_name, method.method_imp, method.method_types); |
128 | 247 |