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