view dstep/objc/bridge/Capsule.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 19885b43130e
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;
	
	alias GC.addRoot addRoot;
	
	import tango.core.Traits;
}

else
{
	import 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;

import mambo.io;

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
	{
		return encapsuleString(decapsule!(Object)(self).toString);
	}
	
	static hash_t hash (id self, SEL op)
	in
	{
		assert(isCapsule(self));
	}
	body
	{
		return decapsule!(Object)(self).toHash;
	}
	
	static byte isEqual (id self, SEL op, Object object)
	in
	{
		assert(isCapsule(self));
	}
	body
	{
		return decapsule!(Object)(self) == object;
	}
}

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);
}

bool isCapsule (id capsule)
{
	if (!capsule)
		return false;
	
	Class cls = capsule.isa;
	return cls.getInstanceVariable!(Bridge.dObjectVar) !is null;
}

ObjcType!(T) encapsule (T) (T value)
{		
	static if (needsEncapsulation!(T))
	{
		if (!value)
			return null;
		
		if (auto wrapper = cast(ObjcWrapper) value)
			return wrapper.objcObject;
		
		return Capsule.create(value, capsuleClass);
	}
	
	else
		return value;
}

T decapsule (T) (ObjcType!(T) value)
{
	static if (needsEncapsulation!(T))
	{
		if (isCapsule(value))
			return cast(T) Bridge.getDObject(value);
		
		else
		{
			static if (is(T : ObjcWrapper))
				new T(value);
			
			else
				return null;
		}
	}
	
	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);
}