| 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 |
} |
|---|