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