diff dstep/objc/bridge/ClassInitializer.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 9fd439a28ce3
children
line wrap: on
line diff
--- a/dstep/objc/bridge/ClassInitializer.d	Mon Aug 03 15:31:48 2009 +0200
+++ b/dstep/objc/bridge/ClassInitializer.d	Sun Jan 03 22:06:11 2010 +0100
@@ -13,114 +13,233 @@
 	import std.math;
 
 import dstep.internal.String;
+import dstep.internal.Traits;
 import bindings = dstep.objc.bindings;
 import dstep.objc.bridge.Bridge;
 import dstep.objc.bridge.TypeEncoding;
 import dstep.objc.objc;
 import dstep.objc.runtime;
 
+/**
+ * Objective-C subclass initializer template.
+ * 
+ * Param:
+ * 	   subclassName = the name of the subclass to create
+ * 	   superClassName = the name of the Objective-C superclass 
+ */
 package template ObjcSubclassInitializer (string subclassName, string superclassName)
-{	
-	import dstep.internal.String : string;
-	import dstep.objc.bridge.Bridge : ObjcBindMethod;
-	import dstep.objc.runtime : Method, objc_method, sel, objc;
-	import dstep.objc.bridge.TypeEncoding : encode;
-	
-	static Class objcClass ()
+{
+	/**
+	 * Return a pointer to the created class data structure. If this class hasn't been added
+	 * to the Objective-C runtime, it'll be added.
+	 *  
+	 * Returns: a pointer to the created class data structure
+	 */
+	static dstep.objc.objc.Class objcClass ()
 	{		
-		if (objcClass_)
-			return objcClass_;
+		if (__objcClass)
+			return __objcClass;
 		
-		Class superClass = cast(Class) objc.getClass!(superclassName);
+		dstep.objc.objc.Class superClass = objcSuperClass;
 		
-		while (!superClass)
-			superClass = super.objcClass;		
-				
-		return objcClass_ = subclassInit!(subclassName)(superClass, collectObjcInstanceMethods, collectObjcClassMethods);
+		auto methods = __collectObjcInstanceMethods();
+		auto classMethods = __collectObjcClassMethods();
+		
+		static if (dstep.internal.Traits.hasClassMethod!(typeof(super), objcClass.stringof))
+			typeof(super).objcClass;
+		
+		return __objcClass = dstep.objc.bridge.ClassInitializer.subclassInit!(subclassName)(superClass, methods, classMethods);
 	}
 	
-	private static Method[] collectObjcInstanceMethods ()
+	/**
+	 * Return a pointer to the superclass data structure. If the superclass hasn't been added
+	 * to the Objective-C runtime, it'll be added.
+	 * 
+	 * Returns: a pointer to the superclass data structure
+	 */
+	static dstep.objc.objc.Class objcSuperClass ()
 	{
-		Method[] methods;
+		if (__objcSuperClass)
+			return __objcSuperClass;
+		
+		if (is(typeof(super) == dstep.objc.bridge.Wrapper.ObjcWrapper)) // root class
+			return __objcSuperClass = dstep.objc.bridge.Capsule.capsuleClass;
+		
+		__objcSuperClass = cast(dstep.objc.objc.Class) dstep.objc.objc.objc.getClass!(subclassName);
+		
+		while (!__objcSuperClass && !is(typeof(super) == dstep.objc.bridge.Wrapper.ObjcWrapper))
+			__objcSuperClass = super.objcClass;
 		
-		mixin("alias " ~ superclassName ~ " Type;");
+		if (!__objcSuperClass)
+			__objcSuperClass = dstep.objc.bridge.Capsule.capsuleClass;
 		
-		foreach (i, f; typeof(Type.tupleof))
+		return __objcSuperClass;
+	}
+	
+	/**
+	 * Collects all binded methods in the class this template is mixed into.
+	 * 
+	 * Returns: an array of methods
+	 */
+	private static dstep.objc.runtime.Method[] __collectObjcInstanceMethods ()
+	{
+		dstep.objc.runtime.Method[] methods;
+		
+		mixin("alias " ~ subclassName ~ " Type;");
+				
+		static if (Type.tupleof.length > 0)
 		{
-			const len = Type.stringof.length;
-			const fieldName = Type.tupleof[i].stringof[1 + len + 2 .. $];
-			
-			static if (fieldName == Bridge.objcMethodDeclarationVar)
+			foreach (i, f ; typeof(Type.tupleof))
 			{
-				typeof(Type.tupleof[i]) field;
+				const len = Type.stringof.length;
+				const fieldName = Type.tupleof[i].stringof[1 + len + 2 .. $];			
+				
+				static if (fieldName == dstep.objc.bridge.Bridge.Bridge.objcMethodDeclarationVar)
+				{				
+					typeof(Type.tupleof[i]) field;
 
-				Method m = new objc_method;
-				m.method_name = sel.registerName!(field.methodName);
-				m.method_types = encode!(field.returnType, id, SEL, field.argsType).ptr;
-				m.method_imp = cast(IMP) &Type.ObjcBindMethod!(field.methodImp, field.returnType, field.methodName, field.argsType).forwardVirtualCall;
-				
-				methods ~= m;
+					dstep.objc.runtime.Method m = new dstep.objc.objc.objc_method;
+					m.method_name = dstep.objc.objc.sel.registerName!(field.methodName);
+					m.method_types = dstep.objc.bridge.TypeEncoding.encode!(field.returnType, dstep.objc.objc.id, dstep.objc.objc.SEL, field.argsType).ptr;
+					m.method_imp = cast(dstep.objc.objc.IMP) field.methodImp;
+					
+					methods ~= m;
+				}
 			}
 		}
 		
 		return methods;
 	}
 	
-	private static Method[] collectObjcClassMethods ()
+	/**
+	 * Collects all binded class methods in the class this template is mixed into.
+	 * 
+	 * Returns:
+	 */
+	private static dstep.objc.runtime.Method[] __collectObjcClassMethods ()
 	{
-		Method[] methods;
+		dstep.objc.runtime.Method[] methods;
 		
-		mixin("alias " ~ superclassName ~ " Type;");
+		mixin("alias " ~ subclassName ~ " Type;");
 		
-		foreach (i, f; typeof(Type.tupleof))
+		static if (Type.tupleof.length > 0)
 		{
-			const len = Type.stringof.length;
-			const fieldName = Type.tupleof[i].stringof[1 + len + 2 .. $];
-			
-			static if (fieldName == Bridge.objcClassMethodDeclarationVar)
+			foreach (i, f ; typeof(Type.tupleof))
 			{
-				typeof(Type.tupleof[i]) field;
-			
-				Method m = new objc_method;
-				m.method_name = sel.registerName!(field.methodName);
-				m.method_types = encode!(field.returnType, field.argsType).ptr;				
-				m.method_imp = cast(IMP) &Type.ObjcBindClassMethod!(field.methodImp, field.returnType, field.methodName, field.argsType).forwardStaticCall;
+				const len = Type.stringof.length;
+				const fieldName = Type.tupleof[i].stringof[1 + len + 2 .. $];
 				
-				methods ~= m;
+				static if (fieldName == dstep.objc.bridge.Bridge.Bridge.objcClassMethodDeclarationVar)
+				{				
+					typeof(Type.tupleof[i]) field;
+
+					dstep.objc.runtime.Method m = new dstep.objc.objc.objc_method;
+					m.method_name = dstep.objc.objc.sel.registerName!(field.methodName);
+					m.method_types = dstep.objc.bridge.TypeEncoding.encode!(field.returnType, field.argsType).ptr;
+					m.method_imp = cast(dstep.objc.objc.IMP) field.methodImp;
+
+					methods ~= m;
+				}
 			}
 		}
 		
 		return methods;
 	}
-
-	private R invokeObjcSelf (R, string name, ARGS...) (ARGS args)
+	
+	/**
+	 * Invoke on the receiver the instance method with the given name, return type
+	 * and arguments.     
+	 * 
+	 * Params:
+	 * 	   R = the return type
+	 *     name = the name (selector) of the method to invoke
+	 *     ARGS = the type of the arguments
+	 *     args = the arguments to the method 
+	 *     
+	 * Returns: whatever the method returns
+	 */
+	private R invokeObjcSelf (R, dstep.internal.String.string name, ARGS...) (ARGS args)
 	{
-		return Bridge.invokeObjcMethod!(R, name, ARGS)(objcObject, args);
+		return dstep.objc.bridge.Bridge.Bridge.invokeObjcMethod!(R, name, ARGS)(this.objcObject, args);
 	}
 	
-	private R invokeObjcSuper (R, string name, ARGS...) (ARGS args)
+	/**
+	 * Invoke on the receiver's super part the instance method with the given name,
+	 * return type and arguments.     
+	 * 
+	 * Params:
+	 *     R = the return type
+	 *     name = the name (selector) of the method to invoke
+	 *     ARGS = the type of the arguments
+	 *     args = the arguments to the method 
+	 *     
+	 * Returns: whatever the method returns
+	 */
+	private R invokeObjcSuper (R, dstep.internal.String.string name, ARGS...) (ARGS args)
 	{
-		return Bridge.invokeObjcMethod!(R, name, ARGS)(objcSuper, args);
+		return dstep.objc.bridge.Bridge.Bridge.invokeObjcSuperMethod!(R, name, ARGS)(this.objcSuper, args);
 	}
 	
-	private static R invokeObjcSelfClass (R, string name, ARGS...) (ARGS args)
+	/**
+	 * Invoke class method with given name, return type and arguments,
+	 * on the receiver's superclass.     
+	 * 
+	 * Params:
+	 * 	   R = the return type
+	 *     name = the name (selector) of the method to invoke
+	 *     ARGS = the type of the arguments
+	 *     args = the arguments to the method 
+	 *     
+	 * Returns: whatever the method returns
+	 */
+	private static R invokeObjcSelfClass (R, dstep.internal.String.string name, ARGS...) (ARGS args)
 	{
-		return Bridge.invokeObjcClassMethod!(R, name, ARGS)(objcClass, args);
+		return dstep.objc.bridge.Bridge.Bridge.invokeObjcClassMethod!(R, name, ARGS)(objcClass, args);
 	}
 	
-	private static R invokeObjcSuperClass (R, string name, ARGS...) (ARGS args)
-	{
-		return Bridge.invokeObjcClassMethod!(R, name, ARGS)(objcSuperClass, args);
+	/**
+	 * Invoke class method with given name, return type and arguments,
+	 * on the receiver's superclass.     
+	 * 
+	 * Params:
+	 * 	   R = the return type
+	 *     name = the name (selector) of the method to invoke
+	 *     ARGS = the type of the arguments
+	 *     args = the arguments to the method 
+	 *     
+	 * Returns: whatever the method returns
+	 */
+	private static R invokeObjcSuperClass (R, dstep.internal.String.string name, ARGS...) (ARGS args)
+	{		
+		return dstep.objc.bridge.Bridge.Bridge.invokeObjcClassMethod!(R, name, ARGS)(objcSuperClass, args);
 	}
 }
 
+/**
+ * Creates a new Objective-C subclass, initializes its data and register it with the
+ * Objective-C runtime.
+ * 
+ * Params:
+ * 	   className = the name of the subclass 
+ *     superClass = the subclass' superclass
+ *     instanceMethods = the instance methods that should be added to the subclass
+ *     classMethods = the class methods that should be added to the subclass
+ *     
+ * Returns: the newly created subclass
+ */
 Class subclassInit (string className) (Class superClass, Method[] instanceMethods = null, Method[] classMethods = null)
 {
-	Class cls = objc.allocateClassPair!(className)(superClass, 0);
+	Class cls;
+	
+	if (objc.getClass!(className))
+		cls = objc.allocateClassPair!("D_" ~ className)(superClass, 0);
+	
+	else
+		cls = objc.allocateClassPair!(className)(superClass, 0);
+	
 	Class metaClass = (cast(id) cls).getClass;
 	
 	ubyte alignment = cast(ubyte) log2(Bridge.DObjectType.sizeof);
-
 	cls.addIvar!(Bridge.dObjectVar, encode!(Bridge.DObjectType))(Bridge.DObjectType.sizeof, alignment);
 	
 	foreach (method ; instanceMethods)