Mercurial > projects > dstep
diff dstep/objc/bridge/Capsule.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/Capsule.d Thu Jun 18 22:00:13 2009 +0200 @@ -0,0 +1,177 @@ +/** + * 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.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; + +template ObjcType (T) +{ + static if (needsEncapsulation!(T)) + alias id ObjcType; + + else + alias T ObjcType; +} + +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; +} + +template needsEncapsulation (T) +{ + static if (is(T == class)) + const needsEncapsulation = true; + + else + const needsEncapsulation = false; +} + +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; +} + +template decapsule (T) +{ + T decapsule (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); +} \ No newline at end of file