comparison d2/qtd/QMetaTypeImpl.d @ 362:bcbfffef4f9e

Undecorated D types can be registered with Qt
author Max Samukha <maxter@maxter.com>
date Wed, 09 Jun 2010 16:37:24 +0300
parents beaf4a2974d7
children a032df77b6ab
comparison
equal deleted inserted replaced
361:beaf4a2974d7 362:bcbfffef4f9e
1 module qtd.QMetaTypeImpl; 1 module qtd.QMetaTypeImpl;
2 2
3 import 3 import
4 std.traits,
5 core.memory,
6 core.exception,
4 qt.core.Qt, 7 qt.core.Qt,
5 qt.core.QDataStream, 8 qt.core.QDataStream,
9 qt.core.QMetaType,
6 qtd.QtdObject; 10 qtd.QtdObject;
7 11
8 // TODO: remove 12 // TODO: remove
9 import std.stdio; 13 import std.stdio;
14 import std.conv;
10 15
11 private struct DArrayToC 16 private struct DArrayToC
12 { 17 {
13 void[] array; 18 void[] array;
14 } 19 }
15 20
16 /** 21 /**
17 */ 22 */
18 template MetaTypeOps(T) 23 template MetaTypeOps(T)
19 { 24 {
25 // Note that in case of byref objects we follow Qt's convention and
26 // allocate/copy references, not objects.
20 static void* construct(void* copy) 27 static void* construct(void* copy)
21 { 28 {
22 static assert (is(T : Object)); 29 auto T* p = cast(T*)GC.malloc(T.sizeof);
23 return cast(void*)new T(cast(T)copy); 30 if (!p)
31 onOutOfMemoryError();
32
33 if (copy)
34 *p = *cast(T*)copy;
35 else
36 {
37 static if (!is(T == class) && __traits(compiles, T()))
38 *p = T();
39 else static if (isAssociativeArray!T)
40 {
41 // COMPILER BUG: need to special-case this because AA.init is broken.
42 // Consequently, no custom AA init values are supported.
43 *p = null;
44 }
45 else
46 *p = T.init;
47 }
48
49 return p;
24 } 50 }
25 51
26 static void destroy(void* ptr) 52 static void destroy(void* ptr)
27 { 53 {
28 (cast(T)ptr).dispose(); 54 // Run destructors for value types. Let the GC reclaim the memory.
55 static if (is(T == struct) && __traits(compiles, T.__dtor))
56 (cast(T*)ptr).__dtor;
29 } 57 }
30 } 58 }
31 59
32 /** 60 /**
33 */ 61 */
42 { 70 {
43 writeln("Loading ", ds.__nativeId, " ", data); 71 writeln("Loading ", ds.__nativeId, " ", data);
44 } 72 }
45 } 73 }
46 74
47 /** 75 // TODO: only GNU C++ is supported
48 */ 76 private template typeOpShim(alias op)
49 int qRegisterMetaType(T, alias ops = MetaTypeOps)(string name = null) 77 {
50 { 78 extern(C) void typeOpShim()
51 if (!name.length)
52 name = typeid(T).toString; //TODO: use compile time full name?
53
54 alias ops!T.construct construct;
55 alias ops!T.destroy destroy;
56
57 // TODO: only GNU C++
58 extern(C) static void ctorShim()
59 { 79 {
60 asm 80 asm
61 { 81 {
62 naked; 82 naked;
63 push EBP; 83 push EBP;
64 mov EBP, ESP; 84 mov EBP, ESP;
65 mov EAX, 0x8[EBP]; 85 mov EAX, 0x8[EBP];
66 call construct; 86 call op;
67 leave; 87 leave;
68 ret; 88 ret;
69 } 89 }
70 } 90 }
71 91 }
72 extern(C) static void dtorShim() 92
73 { 93 /**
74 asm 94 */
75 { 95 int qRegisterMetaType(T, alias ops = MetaTypeOps)(string name = null)
76 naked; 96 {
77 push EBP; 97 if (!name.length)
78 mov EBP, ESP; 98 name = typeid(T).toString; //TODO: use compile time full name
79 mov EAX, 0x8[EBP]; 99
80 call destroy; 100 return qtd_registerType(toStringz(name), &typeOpShim!(ops!T.destroy), &typeOpShim!(ops!T.construct));
81 leave; 101 }
82 ret; 102
83 } 103 version (QtdUnittest)
84 } 104 {
85 105 unittest
86 return qtd_registerType(toStringz(name), &dtorShim, &ctorShim); 106 {
107 static class A
108 {
109 int x;
110 }
111
112 static struct S
113 {
114 int x;
115
116 static S* dtorCalled;
117
118 static S opCall(int x = 31)
119 {
120 S s;
121 s.x = x;
122 return s;
123 }
124
125 ~this()
126 {
127 dtorCalled = &this;
128 }
129 }
130
131 static void test(T)(T val, string typeName = null)
132 {
133 int id = qRegisterMetaType!T(typeName);
134 assert(id > 0);
135 auto p = cast(T*)QMetaType.construct(id, null);
136
137 assert(*p is T.init);
138 QMetaType.destroy(id, p);
139
140 p = cast(T*)QMetaType.construct(id, &val);
141 assert(p !is &val);
142 assert(*p == val);
143 QMetaType.destroy(id, p);
144 }
145
146 test(42, "d_int");
147 test(new A);
148 test([1, 2, 3]);
149
150 int sId = qRegisterMetaType!S();
151 int saId = qRegisterMetaType!(int[3])();
152 int aaId = qRegisterMetaType!(int[int])();
153
154 // structs
155 auto s = S(42);
156
157 auto ps1 = cast(S*)QMetaType.construct(sId, null);
158 assert(ps1.x == 31);
159
160 auto ps2 = cast(S*)QMetaType.construct(sId, &s);
161 assert(ps2 !is &s);
162 assert(ps2.x == 42);
163
164 QMetaType.destroy(sId, ps1);
165 assert(S.dtorCalled is ps1);
166
167 QMetaType.destroy(sId, ps2);
168 assert(S.dtorCalled is ps2);
169
170 // static arrays
171 int sa[3] = [42, 43, 44];
172 auto psa = cast(int[3]*)QMetaType.construct(saId, null);
173 assert(*psa == [0, 0, 0] /* int[3].init */);
174 QMetaType.destroy(saId, psa);
175
176 auto psa2 = cast(int[3]*)QMetaType.construct(saId, &sa);
177 assert(psa2 !is &sa);
178 assert(*psa2 == sa);
179
180 // associative arrays
181 int[int] aa = [1: 42, 2: 43, 3: 44];
182 auto paa = cast(int[int]*)QMetaType.construct(aaId, null);
183 // COMPILER BUG: AA.init is broken
184 // assert (*paa == (int[int]).init);
185 assert(!(*paa).length);
186 QMetaType.destroy(aaId, paa);
187
188 auto paa2 = cast(int[int]*)QMetaType.construct(aaId, &aa);
189 assert(paa2 !is &aa);
190 assert(*paa2 == aa);
191 QMetaType.destroy(aaId, paa);
192 }
87 } 193 }
88 194
89 195
90 // COMPILER BUG: cannot put this inside qRegisterMetaTypeStreamOperators 196 // COMPILER BUG: cannot put this inside qRegisterMetaTypeStreamOperators
91 // COMPILER BUG 2: cannot use extern(C) with templated functions: extern(C) void foo(T)(){} 197 // COMPILER BUG 2: cannot use extern(C) with templated functions: extern(C) void foo(T)(){}