1
|
1 /**
|
|
2 * Copyright: Copyright (c) 2009 Jacob Carlborg.
|
|
3 * Authors: Jacob Carlborg
|
|
4 * Version: Initial created: Feb 3, 2009
|
|
5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
|
|
6 */
|
|
7 module dstep.objc.bridge.Capsule;
|
|
8
|
|
9 version (Tango)
|
|
10 {
|
|
11 import tango.core.Memory;
|
|
12 import tango.math.Math : log2;
|
|
13
|
|
14 alias GC.addRoot addRoot;
|
|
15
|
|
16 import tango.core.Traits;
|
|
17 }
|
|
18
|
|
19 else
|
|
20 {
|
|
21 import std.gc : addRoot;
|
|
22 import std.math : log2;
|
|
23 }
|
|
24
|
|
25 import dstep.internal.String;
|
|
26 import dstep.objc.bridge.Bridge;
|
|
27 import dstep.objc.bridge.TypeEncoding;
|
|
28 import dstep.objc.bridge.Wrapper;
|
|
29 import dstep.objc.message;
|
|
30 import dstep.objc.objc;
|
|
31 import dstep.objc.runtime;
|
|
32 import bindings = dstep.objc.bindings;
|
|
33
|
|
34 import mambo.io;
|
|
35
|
|
36 template ObjcType (T)
|
|
37 {
|
|
38 static if (needsEncapsulation!(T))
|
|
39 alias id ObjcType;
|
|
40
|
|
41 else
|
|
42 alias T ObjcType;
|
|
43 }
|
|
44
|
|
45 Class capsuleClass ()
|
|
46 {
|
|
47 if (!Capsule.capsuleClass)
|
|
48 initCapsuleClass;
|
|
49
|
|
50 return Capsule.capsuleClass;
|
|
51 }
|
|
52
|
|
53 private struct Capsule
|
|
54 {
|
|
55 static Class capsuleClass;
|
|
56
|
|
57 static id create (Object object, Class capsuleClass)
|
|
58 {
|
|
59 id capsule = objc.createInstance(capsuleClass, 0);
|
|
60
|
|
61 Bridge.setDObject(object, capsule);
|
|
62
|
|
63 return capsule;
|
|
64 }
|
|
65
|
|
66 static id description (id self, SEL op)
|
|
67 in
|
|
68 {
|
|
69 assert(isCapsule(self));
|
|
70 }
|
|
71 body
|
|
72 {
|
|
73 return encapsuleString(decapsule!(Object)(self).toString);
|
|
74 }
|
|
75
|
|
76 static hash_t hash (id self, SEL op)
|
|
77 in
|
|
78 {
|
|
79 assert(isCapsule(self));
|
|
80 }
|
|
81 body
|
|
82 {
|
|
83 return decapsule!(Object)(self).toHash;
|
|
84 }
|
|
85
|
|
86 static byte isEqual (id self, SEL op, Object object)
|
|
87 in
|
|
88 {
|
|
89 assert(isCapsule(self));
|
|
90 }
|
|
91 body
|
|
92 {
|
|
93 return decapsule!(Object)(self) == object;
|
|
94 }
|
|
95 }
|
|
96
|
|
97 private void initCapsuleClass ()
|
|
98 {
|
|
99 Class superClass = cast(Class) objc.getClass!("NSObject");
|
|
100 Capsule.capsuleClass = objc.allocateClassPair!("D_Object")(superClass, 0);
|
|
101
|
|
102 ubyte alignment = cast(ubyte) log2(Bridge.DObjectType.sizeof);
|
|
103
|
|
104 Capsule.capsuleClass.addIvar!(Bridge.dObjectVar, encode!(Bridge.DObjectType))(Bridge.DObjectType.sizeof, alignment);
|
|
105
|
|
106 Capsule.capsuleClass.addMethod!(encodeCallable!(Capsule.description))(sel.registerName!("description"), cast(IMP) &Capsule.description);
|
|
107 Capsule.capsuleClass.addMethod!(encodeCallable!(Capsule.hash))(sel.registerName!("hash"), cast(IMP) &Capsule.hash);
|
|
108 Capsule.capsuleClass.addMethod!(encodeCallable!(Capsule.isEqual))(sel.registerName!("isEqual"), cast (IMP) &Capsule.isEqual);
|
|
109
|
|
110 objc.registerClassPair(capsuleClass);
|
|
111 }
|
|
112
|
|
113 bool isCapsule (id capsule)
|
|
114 {
|
|
115 if (!capsule)
|
|
116 return false;
|
|
117
|
|
118 Class cls = capsule.isa;
|
|
119 return cls.getInstanceVariable!(Bridge.dObjectVar) !is null;
|
|
120 }
|
|
121
|
|
122 template needsEncapsulation (T)
|
|
123 {
|
|
124 static if (is(T == class))
|
|
125 const needsEncapsulation = true;
|
|
126
|
|
127 else
|
|
128 const needsEncapsulation = false;
|
|
129 }
|
|
130
|
|
131 ObjcType!(T) encapsule (T) (T value)
|
|
132 {
|
|
133 static if (needsEncapsulation!(T))
|
|
134 {
|
|
135 if (!value)
|
|
136 return null;
|
|
137
|
|
138 if (auto wrapper = cast(ObjcWrapper) value)
|
|
139 return wrapper.objcObject;
|
|
140
|
|
141 return Capsule.create(value, capsuleClass);
|
|
142 }
|
|
143
|
|
144 else
|
|
145 return value;
|
|
146 }
|
|
147
|
|
148 template decapsule (T)
|
|
149 {
|
|
150 T decapsule (ObjcType!(T) value)
|
|
151 {
|
|
152 static if (needsEncapsulation!(T))
|
|
153 {
|
|
154 if (isCapsule(value))
|
|
155 return cast(T) Bridge.getDObject(value);
|
|
156
|
|
157 else
|
|
158 {
|
|
159 static if (is(T : ObjcWrapper))
|
|
160 new T(value);
|
|
161
|
|
162 else
|
|
163 return null;
|
|
164 }
|
|
165 }
|
|
166
|
|
167 else
|
|
168 return value;
|
|
169 }
|
|
170 }
|
|
171
|
|
172 private id encapsuleString (string str)
|
|
173 {
|
|
174 enum { NSUTF8StringEncoding = 4 }
|
|
175
|
|
176 return objc.getClass!("NSString").msgSend(sel.registerName!("alloc")).msgSend(sel.registerName!("initWithBytes:length:encoding:"), str.ptr, str.length, NSUTF8StringEncoding);
|
|
177 } |