view dstep/objc/bridge/Capsule.d @ 24:ab33fc0c3fc1

Fixed the implementation for the methods in Capsule. Changed a method name in objc_class
author Jacob Carlborg <doob@me.com>
date Wed, 10 Feb 2010 19:24:32 +0100
parents 19885b43130e
children b9de51448c6b
line wrap: on
line source

/**
 * Copyright: Copyright (c) 2009 Jacob Carlborg.
 * Authors: Jacob Carlborg
 * Version: Initial created: Feb 3, 2009
 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
 */
module dstep.objc.bridge.Capsule;

version (Tango)
{
	import tango.core.Memory;
	import tango.math.Math : log2;
	
	import tango.core.Traits;
}

else
{
	import GC = std.gc : addRoot;
	import std.math : log2;
}

import dstep.internal.String;
import dstep.objc.bridge.Bridge;
import dstep.objc.bridge.Type;
import dstep.objc.bridge.TypeEncoding;
import dstep.objc.bridge.Wrapper;
import dstep.objc.message;
import dstep.objc.objc;
import dstep.objc.runtime;
import bindings = dstep.objc.bindings;

/// Returns the capsule class
Class capsuleClass ()
{
	if (!Capsule.capsuleClass)
		initCapsuleClass;
	
	return Capsule.capsuleClass;	
}

private struct Capsule
{	
	static Class capsuleClass;
	
	static id create (Object object, Class capsuleClass)
	{
		id capsule = objc.createInstance(capsuleClass, 0);
		
		Bridge.setDObject(object, capsule);
		
		return capsule;
	}
	
	static id description (id self, SEL op)
	in
	{
		assert(isCapsule(self));
	}
	body
	{
		if (auto object = decapsule!(Object)(self))
			return encapsuleString(object.toString);
		
		objc_super superObject;
		superObject.cls = .capsuleClass.getSuperclass;
		superObject.receiver = self;
		
		return Bridge.invokeObjcSuperMethod!(id, "description")(&superObject);
	}
	
	static hash_t hash (id self, SEL op)
	in
	{
		assert(isCapsule(self));
	}
	body
	{
		if (auto object = decapsule!(Object)(self))
			return object.toHash;
		
		objc_super superObject;
		superObject.cls = .capsuleClass.getSuperclass;
		superObject.receiver = self;
		
		return Bridge.invokeObjcSuperMethod!(hash_t, "hash")(&superObject);
	}
	
	static bool isEqual (id self, SEL op, Object other)
	in
	{
		assert(isCapsule(self));
	}
	body
	{
		if (auto object = decapsule!(Object)(self))
			return cast(bool) (object == other);
		
		objc_super superObject;
		superObject.cls = .capsuleClass.getSuperclass;
		superObject.receiver = self;
		
		return Bridge.invokeObjcSuperMethod!(bool, "isEqual:", Object)(&superObject, other);
	}
}

private void initCapsuleClass ()
{
	Class superClass = cast(Class) objc.getClass!("NSObject");
	Capsule.capsuleClass = objc.allocateClassPair!("D_Object")(superClass, 0);
	
	ubyte alignment = cast(ubyte) log2(Bridge.DObjectType.sizeof);
	
	Capsule.capsuleClass.addIvar!(Bridge.dObjectVar, encode!(Bridge.DObjectType))(Bridge.DObjectType.sizeof, alignment);
	
	Capsule.capsuleClass.addMethod!(encodeCallable!(Capsule.description))(sel.registerName!("description"), cast(IMP) &Capsule.description);
	Capsule.capsuleClass.addMethod!(encodeCallable!(Capsule.hash))(sel.registerName!("hash"), cast(IMP) &Capsule.hash);
	Capsule.capsuleClass.addMethod!(encodeCallable!(Capsule.isEqual))(sel.registerName!("isEqual"), cast (IMP) &Capsule.isEqual);
	
	objc.registerClassPair(capsuleClass);
}

/**
 * Returns $(D_KEYWORD true) if the given Objective-C instance is a capsule
 * 
 * Params:
 *     instance = the Objective-C instance 
 *     
 * Returns: $(D_KEYWORD true) if the given Objective-C instance is a capsule
 */
bool isCapsule (id instance)
{	
	//if (capsule && capsule.isa)
		//return capsule.isa.getInstanceVariable!(Bridge.dObjectVar) !is null;
	
	if (instance)
	{
		Class cls = instance.isa;
		
		while (cls && cls !is capsuleClass)
			cls = cls.super_class;
		
		return cls is capsuleClass;
	}
	
	return false;
}

/**
 * Returns $(D_KEYWORD true) if the given Objective-C class is a capsule
 * 
 * Params:
 *     cls = the Objective-C class 
 *     
 * Returns: true if the given Objective-C class is a capsule
 */
bool isCapsule (Class cls)
{	
	while (cls && cls !is capsuleClass)
		cls = cls.super_class;
	
	return cls is capsuleClass;
}

/**
 * Encapsulate the value of type $(D_PARAM T) to corresponding Objective-C type $(D_PSYMBOL ObjcType!(T))
 * 
 * Params:
 * 	   T = the type of the value
 *     value = the value to encapsulate
 *     
 * Returns: the encapsulated value
 */
ObjcType!(T) encapsule (T) (T value)
{		
	static if (needsEncapsulation!(T))
	{
		if (!value)
			return null;
		
		if (auto wrapper = cast(ObjcWrapper) value)
			return wrapper.objcObject;
		
		static if (is(T == interface))
			return Capsule.create(cast(Object) value, capsuleClass);
		
		return Capsule.create(cast(Object) value, capsuleClass);
	}
	
	else
		return value;
}

/**
 * Decapsulate the given Objective-C value of type $(D_PSYMBOL ObjcType!(T)) to corresponding D type $(D_PARAM T). 
 * 
 * Params:
 * 	   T = the type of the decapsulated value
 *     value = the value to decapsulate
 *     
 * Returns: the decapsulated value
 */
T decapsule (T) (ObjcType!(T) value)
{
	static if (needsEncapsulation!(T))
	{		
		static if (hasIdConstructor!(T))
		{
			T instance = cast(T) Bridge.getDObject(value);
			
			return instance ? instance : new T(value);
		}
		
		else
			return cast(T) Bridge.getDObject(value);
	}
	
	else
		return value;
}

private id encapsuleString (string str)
{
	enum { NSUTF8StringEncoding = 4 }
	
	return objc.getClass!("NSString").msgSend(sel.registerName!("alloc")).msgSend(sel.registerName!("initWithBytes:length:encoding:"), str.ptr, str.length, NSUTF8StringEncoding);
}