Mercurial > projects > dstep
diff dstep/objc/bridge/Bridge.d @ 1:033d260cfc9b
First upload of the bridge
author | Jacob Carlborg <doob@me.com> |
---|---|
date | Thu, 18 Jun 2009 22:00:13 +0200 |
parents | |
children | 9fd439a28ce3 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dstep/objc/bridge/Bridge.d Thu Jun 18 22:00:13 2009 +0200 @@ -0,0 +1,431 @@ +/** + * Copyright: Copyright (c) 2009 Jacob Carlborg. + * Authors: Jacob Carlborg + * Version: Initial created: Feb 4, 2009 + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) + */ +module dstep.objc.bridge.Bridge; + +import mambo.io; + +version (Tango) +{ + import tango.core.Memory; + import tango.core.Traits : ParameterTupleOf, ReturnTypeOf; + + alias GC.addRoot addRoot; +} + +else +{ + import std.gc : addRoot; + import std.traits : ParameterTypeTuple, ReturnType; + + alias ReturnType ReturnTypeOf; + alias ParameterTypeTuple ParameterTupleOf; +} + +import dstep.internal.String; +import dstep.internal.Tuple; +import dstep.internal.Version; +import dstep.objc.bridge.Capsule; +import dstep.objc.bridge.ClassInitializer; +import dstep.objc.bridge.TypeEncoding; +import dstep.objc.bridge.Wrapper; +import dstep.objc.message; +import dstep.objc.objc; +import dstep.objc.runtime; + +/** + * Builds a string representing a selector out of the given function + * + * It will build the string like this: + * + * --- + * foo (int x, int y); // foo:y: + * bar (); // bar + * fooBar (int x); // fooBar: + * --- + * + * Params: + * func = the function alias to build the selector of + * + * Returns: a string representing the selector + */ +template selector (alias func) +{ + const selector = buildSelector!(func); +} + +template ObjcWrap () +{ + mixin ObjcWrap!(this.stringof); +} + +template ObjcWrap (string name) +{ + import dstep.objc.bridge.ClassInitializer : ObjcSubclassInitializer, subclassInit; + import dstep.objc.objc : Class, id, IMP, SEL; + + static private Class objcClass_; + static private Class objcSuperClass_; + + this (id object) + { + super(object); + } + + static typeof(this) alloc () + { + return invokeObjcSelfClass!(typeof(this), "alloc"); + } + + typeof(this) init () + { + id ret = invokeObjcSelf!(id, "init"); + + if (!ret) + return null; + + if (ret is objcObject) + { + dObject = this; + return this; + } + + auto object = new typeof(this) (ret); + object.dObject = this; + + return object; + } + + mixin ObjcSubclassInitializer!("D_" ~ name, name); +} + +struct ObjcMethodDeclaration (alias imp, R, string name, ARGS...) +{ + alias imp methodImp; + alias R returnType; + const string methodName = name; + alias ARGS argsType; +} + +template ObjcBindMethod (alias method) +{ + import dstep.objc.bridge.TypeEncoding : buildSelector, encode; + + mixin ObjcBindMethod!(method, buildSelector!(method)); +} + +template ObjcBindMethod (alias method, string selector) +{ + mixin ObjcBindMethod!(method, ReturnTypeOf!(method), selector, ParameterTupleOf!(method)); +} + +template ObjcBindMethod (alias method, R, string selector, ARGS...) +{ + import dstep.objc.bridge.Capsule : decapsule, encapsule, isCapsule, needsEncapsulation; + import dstep.internal.Tuple; + + private ObjcMethodDeclaration!(method, R, selector, ARGS) objcMethodDeclaration; + + private R delegate (ARGS) resolveVirtualCall () + { + return null; + } + + static if (needsEncapsulation!(R)) + { + private alias ReplaceAllClasses!(id, ARGS) ObjcArgs; + + private static id forwardVirtualCall (id self, SEL cmd, ObjcArgs objcArgs) + in + { + assert(isCapsule(self)); + } + body + { + R delegate (ARGS) dg; + dg.funcptr = &method; + dg.ptr = Bridge.getDObject(self); + + ARGS args; + + foreach (i, a ; objcArgs) + { + alias typeof(args[i]) ArgType; + + args[i] = decapsule!(ArgType)(a); + } + + auto result = dg(args); + + return encapsule!(R)(result); + } + } + + else + { + private alias ReplaceAllClasses!(id, ARGS) ObjcArgs; + + private static R forwardVirtualCall (id self, SEL cmd, ObjcArgs objcArgs) + in + { + assert(isCapsule(self)); + } + body + { + R delegate (ARGS) dg; + dg.funcptr = &method; + dg.ptr = Bridge.getDObject(self); + + ARGS args; + + foreach (i, a ; objcArgs) + { + alias typeof(args[i]) ArgType; + + args[i] = decapsule!(ArgType)(a); + } + + return dg(args); + } + } +} + +template ObjcBindClassMethod (alias method, string selector) +{ + mixin ObjcBindClassMethod!(method, ReturnTypeOf!(method), selector, ParameterTupleOf!(method)); +} + +template ObjcBindClassMethod (alias method, R, string selector, ARGS...) +{ + private ObjcMethodDeclaration!(method, R, selector, ARGS) objcClassMethodDeclaration; + + static if (needsEncapsulation!(R)) + { + private alias ReplaceAllClasses!(id, ARGS) ObjcArgs; + + private static id forwardStaticCall (id self, SEL cmd, ObjcArgs objcArgs) + in + { + assert(isCapsule(self)); + } + body + { + R function (ARGS) dg = &method; + + ARGS args; + + foreach (i, a ; objcArgs) + { + alias typeof(args[i]) ArgType; + + args[i] = decapsule!(ArgType)(a); + } + + auto result = dg(args); + + return encapsule!(R)(result); + } + } + + else + { + private alias ReplaceAllClasses!(id, ARGS) ObjcArgs; + + private static R forwardStaticCall (id self, SEL cmd, ObjcArgs objcArgs) + in + { + assert(isCapsule(self)); + } + body + { + R function (ARGS) dg = &method; + + ARGS args; + + foreach (i, a ; objcArgs) + { + alias typeof(args[i]) ArgType; + + args[i] = decapsule!(ArgType)(a); + } + + return dg(args); + } + } +} + +struct Bridge +{ + static: + + const objcMethodDeclarationVar = "objcMethodDeclaration"; + const objcClassMethodDeclarationVar = "objcClassMethodDeclaration"; + const dObjectVar = "dObject"; + alias void* DObjectType; + private ClassInfo[string] registeredClasses; + + void registerClass (string className, ClassInfo classInfo) + { + if (className.length > 2 && className[0 .. 2] == "D_") + registeredClasses[className[0 .. 2]] = classInfo; + + else + registeredClasses[className] = classInfo; + } + + Object createRegisteredObject (T) (string className) + { + return null; + } + + DObjectType getDObject (id self) + { + DObjectType dObject; + + self.getInstanceVariable!(DObjectType, dObjectVar)(dObject); + + return dObject; + } + + id setDObject (Object dObject, id objcObject) + { + auto o = cast(DObjectType) dObject; + addRoot(o); + + objcObject.setInstanceVariable!(DObjectType, Bridge.dObjectVar)(o); + + return objcObject; + } + + R invokeObjcMethod (R, string selector, ARGS...) (id self, ARGS args) + { + static if (!is(R : void)) + R result; + + SEL sel = sel.registerName!(selector); + + alias ReplaceAllClasses!(id, ARGS) ObjcArgs; + ObjcArgs objcArgs; + + foreach (i, a ; args) + { + alias typeof(a) ArgType; + + objcArgs[i] = encapsule!(ArgType)(a); + } + + static if (is(R == struct)) + { + self.msgSend_stret(result, sel, objcArgs); + return result; + } + + else static if (is(R == float) || is(R == double) || is(R == real)) + { + version (X86) + { + static if (is(R == float)) + return self.msgSend_fpret!(R)(sel, objcArgs); + + else + return self.msgSend_fpret(sel, objcArgs); + } + + else version (X86_64) + { + static if (is(R == real)) + return self.msgSend_fpret(sel, objcArgs); + + else + return self.msgSend!(R)(sel, objcArgs); + } + + else + return self.msgSend!(R)(sel, objcArgs); + } + + else static if (is(R : ObjcWrapper)) + { + id r = self.msgSend(sel, objcArgs); + + if (!r) + return null; + + if (isCapsule(r)) + { + result = decapsule!(R)(r); + + if (result) + return result; + } + + return new R(r); + } + + else static if (is(R : Object)) + { + id r = self.msgSend(sel, objcArgs); + + if (!r) + return null; + + return decapsule!(R)(r); + } + + else + return self.msgSend!(R, ObjcArgs)(sel, objcArgs); + } + + R invokeObjcClassMethod (R = id, string selector, ARGS...) (Class cls, ARGS args) + { + return invokeObjcMethod!(R, selector, ARGS)(cast(id) cls, args); + } + + R invokeObjcSuperMethod (R = id, string selector, ARGS...) (objc_super* self, ARGS args) + { + R result; + SEL sel = sel.registerName!(selector); + + alias ReplaceAllClasses!(id, ARGS) ObjcArgs; + ObjcArgs objcArgs; + + foreach (i, a ; args) + { + alias typeof(a) ArgType; + + objcArgs[i] = encapsule!(ArgType)(a); + } + + static if (is(R == struct)) + { + self.msgSendSuper_stret(result, sel, objcArgs); + } + + else static if (is(R : ObjcWrapper)) + { + id r = self.msgSendSuper(sel, objcArgs); + + if (isCapsule(r)) + { + result = decapsule!(R)(r); + + if (result) + return result; + } + + return r ? new R(r) : null; + } + + else static if (is(R : Object)) + { + id r = self.msgSendSuper(sel, objcArgs); + return decapsule!(R)(r); + } + + else + return self.msgSend!(R)(sel, objcArgs); + } +} \ No newline at end of file