view dstep/objc/bridge/Bridge.d @ 2:9fd439a28ce3

Adapted the scripts for the new bridge + a lot more
author Jacob Carlborg <doob@me.com>
date Sun, 05 Jul 2009 17:16:19 +0200
parents 033d260cfc9b
children 07194b026fa4
line wrap: on
line source

/**
 * 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)
{
	private
	{
		import dstep.objc.bridge.ClassInitializer : ObjcSubclassInitializer, subclassInit;
		import dstep.objc.objc : Class, id, IMP, SEL;
	
		static Class objcClass_;
		static Class objcSuperClass_;
	}
	
	this ()
	{
		objcObject = invokeObjcSelfClass!(id, "alloc");
		id ret = invokeObjcSelf!(id, "init");
		
		if (ret)
			objcObject = ret;
		
		dObject = this;
	}

	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...)
{	
	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 ()
		{
			return null;
		}
		
		alias ReplaceAllClasses!(id, ARGS) ObjcArgs;
		
		static ObjcType!(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);
			}
			
			static if (is(R == void))
				dg(args);
			
			else
				return encapsule!(R)(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
	{
		import dstep.objc.bridge.Capsule : decapsule, encapsule, isCapsule, needsEncapsulation, ObjcType;
		import dstep.internal.Tuple;
		
		ObjcMethodDeclaration!(method, R, selector, ARGS) objcClassMethodDeclaration;
		
		alias ReplaceAllClasses!(id, ARGS) ObjcArgs;
		
		static ObjcType!(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);
			}
			
			static if (needsEncapsulation!(R))
				return encapsule!(R)(dg(args));
			
			else
				return dg(args);
		}
	}
}

template ObjcBindFunction (alias func)
{
	mixin ObjcBindFunction!(func, ReturnTypeOf!(func), ParameterTupleOf!(func));
}

template ObjcBindFunction (alias func, R, ARGS...)
{
	private
	{
		import dstep.objc.bridge.Capsule : decapsule, encapsule, needsEncapsulation, ObjcType;
		import dstep.internal.Tuple;
		
		ObjcMethodDeclaration!(method, R, selector, ARGS) objcClassMethodDeclaration;
		
		alias ReplaceAllClasses!(id, ARGS) ObjcArgs;
		
		extern (C) ObjcType!(R) forwardFunctionCall (ObjcArgs objcArgs)
		{			
			ARGS args;
			
			foreach (i, a ; objcArgs)
			{
				alias typeof(args[i]) ArgType;
				
				args[i] = decapsule!(ArgType)(a);
			}
			
			static if (needsEncapsulation!(R))
				return encapsule!(R)(dg(args));
			
			else
				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);
	}
	
	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;
		
		foreach (i, a ; args)
		{
			alias typeof(a) ArgType;
			
			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);
		}
		
		else
			return funcPtr(objcArgs);
	}
}