Mercurial > projects > dstep
diff dstep/objc/bridge/Bridge.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 | 07194b026fa4 |
children | b2693af5a569 |
line wrap: on
line diff
--- a/dstep/objc/bridge/Bridge.d Mon Aug 03 15:31:48 2009 +0200 +++ b/dstep/objc/bridge/Bridge.d Sun Jan 03 22:06:11 2010 +0100 @@ -10,13 +10,11 @@ { import tango.core.Memory; import tango.core.Traits : ParameterTupleOf, ReturnTypeOf; - - alias GC.addRoot addRoot; } else { - import std.gc : addRoot; + import GC = std.gc : addRoot; import std.traits : ParameterTypeTuple, ReturnType; alias ReturnType ReturnTypeOf; @@ -24,10 +22,10 @@ } 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.Type; import dstep.objc.bridge.TypeEncoding; import dstep.objc.bridge.Wrapper; import dstep.objc.message; @@ -35,282 +33,676 @@ import dstep.objc.runtime; /** - * Builds a string representing a selector out of the given function + * Builds a string representing a selector out of the given method * - * It will build the string like this: + * It will build the string using the parameter names as a part of the selector, + * like this: * + * Examples: * --- - * foo (int x, int y); // foo:y: - * bar (); // bar - * fooBar (int x); // fooBar: + * foo (int x, int y); + * bar (); + * fooBar (int x); + * + * static assert(selectorAsString!(foo) == "foo:y:"); + * static assert(selectorAsString!(bar) == "bar"); + * static assert(selectorAsString!(fooBar) == "fooBar:"); * --- * * Params: - * func = the function alias to build the selector of + * method = the method alias to build the selector of * * Returns: a string representing the selector */ -template selector (alias func) +template selectorAsString (alias method) { - const selector = buildSelector!(func); + const selectorAsString = buildSelector!(method); } -template ObjcWrap () +/** + * Registers a method with the Objective-C runtime system, + * maps the method name to a selector, and returns the selector value. + * + * You must register a method name with the Objective-C runtime system to obtain + * the method’s selector before you can add the method to a class definition. + * If the method name has already been registered, this function simply returns + * the selector. + * + * Examples: + * --- + * SEL sel = selector!("foo:"); + * --- + * + * Params: + * str = the string to register + * + * Returns: a pointer of type SEL specifying the selector for the named method. + */ +SEL selector (string str) () { - mixin ObjcWrap!(this.stringof); + return sel.registerName!(str); +} + +/** + * Registers a method with the Objective-C runtime system, + * maps the method name to a selector, and returns the selector value. + * + * Using selectorAsString to get the string representation of the selector. + * + * You must register a method name with the Objective-C runtime system to obtain + * the method’s selector before you can add the method to a class definition. + * If the method name has already been registered, this function simply returns + * the selector. + * + * Examples: + * --- + * foo (int x); + * SEL sel = selector!(foo); + * --- + * + * Params: + * method = the method to register + * + * Returns: a pointer of type SEL specifying the selector for the named method. + */ +SEL selector (alias method) () +{ + return sel.registerName!(selectorAsString!(method)); } -template ObjcWrap (string name) -{ - private +/** + * All Objective-C wrappers should mix in this string. + * + * Mixes in: + * $(UL + * $(LI $(D_PSYMBOL __objcClass): a class variable representing the Objective-C class) + * $(LI $(D_PSYMBOL __objcSuperClass): a class variable representing the Objective-C super class) + * $(LI A constructor taking an Objective-C instance) + * $(LI $(D_PSYMBOL dstep.objc.bridge.ClassInitializer.ObjcSubclassInitializer)) + * ) + * + * Examples: + * --- + * class AppController : NSObject + * { + * mixin(ObjcWrap); + * } + * --- + */ +const ObjcWrap = "static private dstep.objc.objc.Class __objcClass; + static private dstep.objc.objc.Class __objcSuperClass; + + this (dstep.objc.objc.id object) { - import dstep.objc.bridge.ClassInitializer : ObjcSubclassInitializer, subclassInit; - import dstep.objc.objc : Class, id, IMP, SEL; - - static Class objcClass_; - static Class objcSuperClass_; + super(object); + } + + static typeof(this) alloc () + { + return invokeObjcSelfClass!(typeof(this), \"alloc\"); } - - this () - { - objcObject = invokeObjcSelfClass!(id, "alloc"); - id ret = invokeObjcSelf!(id, "init"); - if (ret) - objcObject = ret; - - dObject = this; - } + mixin dstep.objc.bridge.ClassInitializer.ObjcSubclassInitializer!(this.stringof, super.stringof);"; - this (id object) +/** + * All Objective-C wrappers should mix in this string. + * + * Mixes in: + * $(UL + * $(LI $(D_PSYMBOL __objcClass): a class variable representing the Objective-C class) + * $(LI $(D_PSYMBOL __objcSuperClass): a class variable representing the Objective-C super class) + * $(LI A constructor taking an Objective-C instance) + * $(LI $(D_PSYMBOL dstep.objc.bridge.ClassInitializer.ObjcSubclassInitializer)) + * ) + * + * Examples: + * --- + * class NSString : NSObject + * { + * mixin(ObjcClusterWrap); + * } + * --- + */ +const ObjcClusterWrap = "static private dstep.objc.objc.Class __objcClass; + static private dstep.objc.objc.Class __objcSuperClass; + + this (dstep.objc.objc.id object) { super(object); } - /*static typeof(this) alloc () - { - return invokeObjcSelfClass!(typeof(this), "alloc"); - }*/ - - /*typeof(this) init () + static typeof(this) alloc () { - 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); -} + return invokeObjcSuperClass!(typeof(this), \"alloc\"); + } + + mixin dstep.objc.bridge.ClassInitializer.ObjcSubclassInitializer!(this.stringof, super.stringof);"; +/** + * This $(D_KEYWORD struct) represents an Objective-C method declaration. + * + * Examples: + * --- + * class C : NSObject + * { + * void foo (int x) {} + * ObjcMethodDeclaration!(foo, void, "foo", int) objcMethodDecl; + * } + * --- + * + * Params: + * imp = the D method + * R = the return type of the method + * name = the name of the method + * ARGS = the argument types of the method + */ struct ObjcMethodDeclaration (alias imp, R, string name, ARGS...) { - alias imp methodImp; + dstep.objc.objc.IMP methodImp = cast(dstep.objc.objc.IMP) &imp; alias R returnType; const string methodName = name; alias ARGS argsType; } +/** + * Binds a selector to an instance method. + * + * This will create a receiver function which will forward the call to $(D_PARAM method), + * decapsulating arguments and encapsulating the return value as appropriate. + * This $(D_KEYWORD template) will use the buildSelector $(D_KEYWORD template) to build + * the selector. It will automatically infer the return type and the argument types + * of the method. + * + * Mixes in: ObjcBindMethod + * + * Examples: + * --- + * class AppController : NSObject + * { + * void foo () {} + * mixin ObjcBindMethod!(foo); + * } + * --- + * + * Params: + * method = the method to bind + */ template ObjcBindMethod (alias method) { - import dstep.objc.bridge.TypeEncoding : buildSelector, encode; - - mixin ObjcBindMethod!(method, buildSelector!(method)); + mixin ObjcBindMethod!(method, dstep.objc.bridge.TypeEncoding.buildSelector!(method)); } +/** + * Binds a selector to an instance method. + * + * This will create a receiver function which will forward the call to $(D_PARAM method), + * decapsulating arguments and encapsulating the return value as appropriate. + * It will automatically infer the return type and the argument types + * of the method. + * + * Mixes in: ObjcBindMethod + * + * Examples: + * --- + * class AppController : NSObject + * { + * void foo () {} + * mixin ObjcBindMethod!(foo, "foo"); + * } + * --- + * + * Params: + * method = the method to bind + * selector = the selector to bind the method to + */ template ObjcBindMethod (alias method, string selector) { - mixin ObjcBindMethod!(method, ReturnTypeOf!(method), selector, ParameterTupleOf!(method)); + version (Tango) + mixin ObjcBindMethod!(method, tango.core.Traits.ReturnTypeOf!(method), selector, tango.core.Traits.ParameterTupleOf!(method)); + + else + mixin ObjcBindMethod!(method, std.traits.ReturnType!(method), selector, std.traits.ParameterTypeTuple!(method)); } +/** + * Binds a selector to an instance method. + * + * This will create a receiver method which will forward the call to $(D_PARAM method), + * decapsulating arguments and encapsulating the return value as appropriate. + * + * Examples: + * --- + * class AppController : NSObject + * { + * int foo (int x) + * { + * return x; + * } + * + * mixin ObjcBindMethod!(foo, int, "foo:", int); + * } + * --- + * + * Params: + * method = the method to bind + * R = the return type of the method + * selector = the selector to bind the method to + * ARGS = the argument types of the method + */ template ObjcBindMethod (alias method, R, string selector, ARGS...) -{ +{ private - { - import dstep.objc.bridge.Capsule : decapsule, encapsule, isCapsule; - import dstep.objc.bridge.Type : needsEncapsulation, ObjcType; - import dstep.internal.Tuple; - - ObjcMethodDeclaration!(method, R, selector, ARGS) objcMethodDeclaration; - - R delegate (ARGS) resolveVirtualCall () + { + /** + * Resolves the virtual call + * + * Returns: a $(D_KEYWORD delegate) to the binded method + */ + R delegate (ARGS) __resolveVirtualCall () { - return null; + return &method; } - alias ReplaceAllClasses!(id, ARGS) ObjcArgs; + /// A type tuple with all the encapsulated types + alias dstep.objc.bridge.Type.ObjcTypes!(ARGS) __ObjcArgs; - static ObjcType!(R) forwardVirtualCall (id self, SEL cmd, ObjcArgs objcArgs) + /** + * The receiver method, this will be the method called from the Objective-C side + * + * Params: + * self = the Objective-C instance to call the method on + * cmd = the Objective-C selector representing the method to call + * objcArgs = the encapsulated arguments to the binded method + * + * Returns: whatever the binded method returns, encapsulated + */ + extern (C) static dstep.objc.bridge.Type.ObjcType!(R) __forwardVirtualCall (dstep.objc.objc.id self, dstep.objc.objc.SEL cmd, __ObjcArgs objcArgs) in { - assert(isCapsule(self)); + assert(dstep.objc.bridge.Capsule.isCapsule(self)); } body - { - R delegate (ARGS) dg; - dg.funcptr = &method; - dg.ptr = Bridge.getDObject(self); - + { + R delegate (ARGS) delegate () dg; + dg.ptr = cast(void*) dstep.objc.bridge.Capsule.decapsule!(typeof(this))(self); + dg.funcptr = &__resolveVirtualCall; ARGS args; foreach (i, a ; objcArgs) { - alias typeof(args[i]) ArgType; - - args[i] = decapsule!(ArgType)(a); + alias typeof(args[i]) ArgType; + args[i] = dstep.objc.bridge.Capsule.decapsule!(ArgType)(a); } static if (is(R == void)) - dg(args); + dg()(args); else - return encapsule!(R)(dg(args)); + return dstep.objc.bridge.Capsule.encapsule!(R)(dg()(args)); } + + /// The Objective-C method declaration for the binded method + ObjcMethodDeclaration!(__forwardVirtualCall, R, selector, ARGS) __objcMethodDeclaration; } } +/** + * Binds a selector to a class (static) method. + * + * This will create a receiver function which will forward the call to $(D_PARAM method), + * decapsulating arguments and encapsulating the return value as appropriate. + * This $(D_KEYWORD template) will use the buildSelector $(D_KEYWORD template) + * to build the selector. It will automatically infer the return type and the + * argument types of the method. + * + * Mixes in: $(D_PSYMBOL ObjcBindClassMethod) + * + * Examples: + * --- + * class AppController : NSObject + * { + * static void foo () {} + * mixin ObjcBindClassMethod!(foo); + * } + * --- + * + * Params: + * method = the method to bind + */ +template ObjcBindClassMethod (alias method) +{ + mixin ObjcBindClassMethod!(method, dstep.objc.bridge.TypeEncoding.buildSelector!(method)); +} + +/** + * Binds a selector to a class (static) method. + * + * This will create a receiver function which will forward the call to $(D_PARAM method), + * decapsulating arguments and encapsulating the return value as appropriate. + * It will automatically infer the return type and the argument types + * of the method. + * + * Mixes in: $(D_PSYMBOL ObjcBindClassMethod) + * + * Examples: + * --- + * class AppController : NSObject + * { + * static void foo () {} + * mixin ObjcBindClassMethod!(foo, "foo"); + * } + * --- + * + * Params: + * method = the method to bind + * selector = the selector to bind the method to + */ template ObjcBindClassMethod (alias method, string selector) { - mixin ObjcBindClassMethod!(method, ReturnTypeOf!(method), selector, ParameterTupleOf!(method)); + version (Tango) + mixin ObjcBindClassMethod!(method, tango.core.Traits.ReturnTypeOf!(method), selector, tango.core.Traits.ParameterTupleOf!(method)); + + else + mixin ObjcBindClassMethod!(method, std.traits.ReturnType!(method), selector, std.traits.ParameterTypeTuple!(method)); } +/** + * Binds a selector to a class (static) method. + * + * This will create a receiver method which will forward the call to $(D_PARAM method), + * decapsulating arguments and encapsulating the return value as appropriate. + * + * Examples: + * --- + * class AppController : NSObject + * { + * static int foo (int x) + * { + * return x; + * } + * + * mixin ObjcBindClassMethod!(foo, int, "foo:", int); + * } + * --- + * + * Params: + * method = the method to bind + * R = the return type of the method + * selector = the selector to bind the method to + * ARGS = the argument types of the method + */ template ObjcBindClassMethod (alias method, R, string selector, ARGS...) -{ +{ private { - import dstep.objc.bridge.Capsule : decapsule, encapsule, isCapsule, needsEncapsulation, ObjcType; - import dstep.internal.Tuple; + /// A type tuple with all the encapsulated types + alias dstep.objc.bridge.Type.ObjcTypes!(ARGS) __ObjcArgs; - ObjcMethodDeclaration!(method, R, selector, ARGS) objcClassMethodDeclaration; - - alias ReplaceAllClasses!(id, ARGS) ObjcArgs; - - static ObjcType!(R) forwardStaticCall (id self, SEL cmd, ObjcArgs objcArgs) + /** + * The receiver method, this will be the method called from the Objective-C side + * + * Params: + * objcArgs = the encapsulated arguments to the binded method + * + * Returns: whatever the binded method returns, encapsulated + */ + extern (C) static dstep.objc.bridge.Type.ObjcType!(R) __forwardStaticCall (dstep.objc.objc.Class self, dstep.objc.objc.SEL cmd, __ObjcArgs objcArgs) in { - assert(isCapsule(self)); + assert(dstep.objc.bridge.Capsule.isCapsule(self)); } body { - R function (ARGS) dg = &method; - + R function (ARGS) funcPtr = &method; ARGS args; foreach (i, a ; objcArgs) { - alias typeof(args[i]) ArgType; - - args[i] = decapsule!(ArgType)(a); + alias typeof(args[i]) ArgType; + args[i] = dstep.objc.bridge.Capsule.decapsule!(ArgType)(a); } - static if (needsEncapsulation!(R)) - return encapsule!(R)(dg(args)); + static if (is(R == void)) + funcPtr()(args); else - return dg(args); + return dstep.objc.bridge.Capsule.encapsule!(R)(funcPtr()(args)); } + + /// The Objective-C method declaration for the binded method + ObjcMethodDeclaration!(__forwardStaticCall, R, selector, ARGS) __objcClassMethodDeclaration; } } +/** + * Binds a D free function to an Objective-C free function. + * + * This will create a receiver function which will forward the call to the + * binded function, decapsulating arguments and encapsulating the return value + * as appropriate. + * + * Mixes in: $(D_PSYMBOL ObjcBindFunction) + * + * Examples: + * --- + * void foo (); + * mixin ObjcBindFunction!(foo); + * --- + */ template ObjcBindFunction (alias func) { mixin ObjcBindFunction!(func, ReturnTypeOf!(func), ParameterTupleOf!(func)); } +/** + * Binds a D free function to an Objective-C free function. + * + * This will create a receiver function which will forward the call to the + * binded function, decapsulating arguments and encapsulating the return value + * as appropriate. + * + * Examples: + * --- + * char foo (int); + * mixin ObjcBindFunction!(foo, char, int); + * --- + * + * Params: + * func = the function to bind + * R = the return type of the function + * ARGS = the argument types of the function + */ template ObjcBindFunction (alias func, R, ARGS...) { private - { - import dstep.objc.bridge.Capsule : decapsule, encapsule, needsEncapsulation, ObjcType; - import dstep.internal.Tuple; + { + /// A type tuple with all the encapsulated types + alias dstep.objc.bridge.Type.ObjcTypes!(ARGS) __ObjcArgs; - ObjcMethodDeclaration!(method, R, selector, ARGS) objcClassMethodDeclaration; - - alias ReplaceAllClasses!(id, ARGS) ObjcArgs; - - extern (C) ObjcType!(R) forwardFunctionCall (ObjcArgs objcArgs) + /** + * The receiver function, this will be the function called from the Objective-C side + * + * Params: + * objcArgs = the encapsulated arguments to the binded function + * + * Returns: whatever the binded function returns, encapsulated + */ + extern (C) dstep.internal.Types.ObjcType!(R) __forwardFunctionCall (__ObjcArgs objcArgs) { + R function (ARGS) funcPtr = &func; ARGS args; foreach (i, a ; objcArgs) { - alias typeof(args[i]) ArgType; - - args[i] = decapsule!(ArgType)(a); + alias typeof(args[i]) ArgType; + args[i] = dstep.objc.bridge.Capsule.decapsule!(ArgType)(a); } - static if (needsEncapsulation!(R)) - return encapsule!(R)(dg(args)); + static if (is(R == void)) + funcPtr()(args); else - return dg(args); + return dstep.objc.bridge.Capsule.encapsule!(R)(funcPtr()(args)); } } } -struct Bridge +/// This $(D_KEYWORD class) acts like a name space for various methods and functions +class Bridge { + private static Bridge bridgeInstance; + + /// The name of the method declaration variable mixed in in a $(D_KEYWORD class) + const objcMethodDeclarationVar = "__objcMethodDeclaration"; + + /// The name of the class method declaration variable mixed in in a $(D_KEYWORD class) + const objcClassMethodDeclarationVar = "__objcClassMethodDeclaration"; + + /// The name of the variable used on the Objective-C side to store the D object + const dObjectVar = "dObject"; + + /// This alias is used as an internal representation of a D object + //alias Object DObjectType; + alias void* DObjectType; + + /** + * Gets the only instance of this class + * + * Returns: the instance + */ + static Bridge instance () + { + if (bridgeInstance) + return bridgeInstance; + + return bridgeInstance = new Bridge; + } + static: - const objcMethodDeclarationVar = "objcMethodDeclaration"; - const objcClassMethodDeclarationVar = "objcClassMethodDeclaration"; - const dObjectVar = "dObject"; - alias void* DObjectType; - private ClassInfo[string] registeredClasses; - - void registerClass (string className, ClassInfo classInfo) + /** + * Gets the value of an Objective-C instance variable + * + * Examples: + * --- + * id self; + * int x = getObjcIvar!(int, "x")(self); + * --- + * + * Params: + * T = the type of the instance variable + * name = the name of the instance variable + * self = the Objective-C instance + * + * Returns: the value of the Objective-C variable + */ + T getObjcIvar (T, string name) (id self) { - if (className.length > 2 && className[0 .. 2] == "D_") - registeredClasses[className[0 .. 2]] = classInfo; + T value; - else - registeredClasses[className] = classInfo; + self.getInstanceVariable!(T, name)(value); + + return value; } - Object createRegisteredObject (T) (string className) + /** + * Sets the value of an Objective-C instance variable + * + * Examples: + * --- + * id self; + * Bridge.setObjcIvar!(int, "x")(self, 3); + * --- + * + * Params: + * T = the type of the instance variable + * name = the name of the instance + * objcObject = the Objective-C instance + * value = the value to set + */ + void setObjcIvar (T, string name) (id self, T value) { - return null; + GC.addRoot(value); + self.setInstanceVariable!(T, dObjectVar)(value); } - DObjectType getDObject (id self) + /** + * Gets the D object stored in the given Objective-C instance + * + * Examples: + * --- + * NSObject object = new NSObject; + * id self = object.objcObject; + * assert(object == Bridge.getDObject(self)); + * --- + * + * Params: + * self = the Objective-C instance + * + * Returns: the D object or null + */ + package DObjectType getDObject (id self) { - DObjectType dObject; - - self.getInstanceVariable!(DObjectType, dObjectVar)(dObject); - - return dObject; + return getObjcIvar!(DObjectType, dObjectVar)(self); } - id setDObject (Object dObject, id objcObject) + /** + * Stores the given D object in the given Objective-C instance + * + * Examples: + * --- + * NSObject object = new NSObject; + * id self = object.objcObject; + * Bridge.setDObject(object, self); + * --- + * + * Params: + * dObject = the D object to store + * objcObject = the Objective-C instance to store the D object in + * + * Returns: the Objective-C instance + */ + package id setDObject (Object dObject, id objcObject) { - auto o = cast(DObjectType) dObject; - addRoot(o); - - objcObject.setInstanceVariable!(DObjectType, Bridge.dObjectVar)(o); + auto o = cast(DObjectType) dObject; + setObjcIvar!(DObjectType, dObjectVar)(objcObject, o); return objcObject; } - - R invokeObjcMethod (R, string selector, ARGS...) (id self, ARGS args) + + /** + * Deregisters the given Objective-C instance from the bridge + * + * Params: + * objcInstance = the Objective-C instance to deregister + */ + package static void deregisterObjcInstance (id objcInstance) { - static if (!is(R : void)) - R result; + GC.removeRoot(getObjcIvar!(DObjectType, dObjectVar)(objcInstance)); + } + + /** + * This method wraps the family of $(D_PSYMBOL objc_msgSend) methods which is used to send a message + * to an instance of a class. + * + * This method chooses the appropriate $(D_PSYMBOL objc_msgSend) method depending on the return value, + * decapsulating arguments and encapsulating the return value as appropriate. + * + * Params: + * R = the return type + * selector = the selector to call + * ARGS = the argument types + * self = the reciver of the call + * args = the arguments to the method + * + * Returns: whatever the method returns, encapsulaed + */ + R invokeObjcMethod (R, string selector, ARGS...) (id self, ARGS args) + { + static assert (checkSelector!(selector, ARGS), "The selector \"" ~ selector ~ "\" and the arguments " ~ ARGS.stringof ~ " do not match"); SEL sel = sel.registerName!(selector); - - alias ReplaceAllClasses!(id, ARGS) ObjcArgs; - ObjcArgs objcArgs; + ObjcTypes!(ARGS) objcArgs; foreach (i, a ; args) { @@ -321,25 +713,21 @@ static if (is(R == struct)) { + R result; 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); - } + return self.msgSend_fpret!(R, ObjcTypes!(ARGS))(sel, objcArgs); else version (X86_64) { static if (is(R == real)) - return self.msgSend_fpret(sel, objcArgs); + return self.msgSend_fpret!(R)(sel, objcArgs); else return self.msgSend!(R)(sel, objcArgs); @@ -349,50 +737,56 @@ 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 static if (needsEncapsulation!(R)) + return decapsule!(R)(self.msgSend(sel, objcArgs)); else - return self.msgSend!(R, ObjcArgs)(sel, objcArgs); + return self.msgSend!(R, ObjcTypes!(ARGS))(sel, objcArgs); } - R invokeObjcClassMethod (R = id, string selector, ARGS...) (Class cls, ARGS args) + /** + * This method wraps the family of $(D_PSYMBOL objc_msgSend) methods which is used to send a message + * to a class. + * + * This method chooses the appropriate $(D_PSYMBOL objc_msgSend) method depending on the return value, + * decapsulating arguments and encapsulating the return value as appropriate. + * + * Params: + * R = the return type + * selector = the selector to call + * ARGS = the argument types + * cls = the reciver of the call + * args = the arguments to the method + * + * Returns: whatever the method returns, encapsulaed + */ + R invokeObjcClassMethod (R, 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; + /** + * This method wraps the family of $(D_PSYMBOL objc_msgSendSuper) methods which is used to send a message + * to an instance of a superclass. + * + * This method chooses the appropriate $(D_PSYMBOL objc_msgSendSuper) method depending on the return value, + * decapsulating arguments and encapsulating the return value as appropriate. + * + * Params: + * R = the return type + * selector = the selector to call + * ARGS = the argument types + * self = the reciver of the call + * args = the arguments to the method + * + * Returns: whatever the method returns, encapsulaed + */ + R invokeObjcSuperMethod (R, string selector, ARGS...) (objc_super* self, ARGS args) + { + static assert (checkSelector!(selector, ARGS), "The selector \"" ~ selector ~ "\" and the arguments " ~ ARGS.stringof ~ " do not match"); + SEL sel = sel.registerName!(selector); - - alias ReplaceAllClasses!(id, ARGS) ObjcArgs; - ObjcArgs objcArgs; + ObjcTypes!(ARGS) objcArgs; foreach (i, a ; args) { @@ -403,43 +797,35 @@ static if (is(R == struct)) { + R result; 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; + return result; } - else static if (is(R : Object)) - { - id r = self.msgSendSuper(sel, objcArgs); - return decapsule!(R)(r); - } + else static if (needsEncapsulation!(R)) + return decapsule!(R)(self.msgSendSuper(sel, objcArgs)); else - return self.msgSend!(R)(sel, objcArgs); + return self.msgSendSuper!(R, ObjcTypes!(ARGS))(sel, objcArgs); } + /** + * This method wraps a call to a regular C free function, decapsulating arguments and + * encapsulating the return value as appropriate. + * + * Params: + * R = the return type + * func = the function to call + * ARGS = the argument types + * args = the arguments to the function + * + * Returns: whatever the method returns, encapsulaed + */ R invokeObjcFunction (R, alias func, ARGS...) (ARGS args) - { - static if (!is(R : void)) - R result; - - auto funcPtr = &func; // use a function pointer instead of the alias because the function can be private. - - alias ReplaceAllClasses!(id, ARGS) ObjcArgs; - ObjcArgs objcArgs; + { + auto funcPtr = &func; // use a function pointer instead of the alias because the function may not be public. + ObjcTypes!(ARGS) objcArgs; foreach (i, a ; args) { @@ -448,35 +834,10 @@ objcArgs[i] = encapsule!(ArgType)(a); } - static if (is(R : ObjcWrapper)) - { - id r = funcPtr(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 = funcPtr(objcArgs); - - if (!r) - return null; - - return decapsule!(R)(r); - } + static if (is(R == void)) + funcPtr(objcArgs); else - return funcPtr(objcArgs); + return decapsule!(R)(funcPtr(objcArgs)); } } \ No newline at end of file