1 /*
2  * DQt - D bindings for the Qt Toolkit
3  *
4  * GNU Lesser General Public License Usage
5  * This file may be used under the terms of the GNU Lesser
6  * General Public License version 3 as published by the Free Software
7  * Foundation and appearing in the file LICENSE.LGPL3 included in the
8  * packaging of this file. Please review the following information to
9  * ensure the GNU Lesser General Public License version 3 requirements
10  * will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
11  */
12 module qt.core.metatype;
13 extern(C++):
14 
15 import qt.config;
16 import qt.core.basicatomic;
17 import qt.core.bytearray;
18 import qt.core.bytearrayview;
19 import qt.core.compare;
20 import qt.core.datastream;
21 import qt.core.flags;
22 import qt.core.global;
23 import qt.core.iterable;
24 import qt.core.object;
25 import qt.core.objectdefs;
26 import qt.core.typeinfo;
27 import qt.helpers;
28 import std.traits;
29 
30 /+ #ifndef QT_NO_QOBJECT
31 #endif
32 
33 #ifdef Bool
34 #error qmetatype.h must be included before any header file that defines Bool
35 #endif
36 
37 
38 // from qcborcommon.h
39 enum class QCborSimpleType : quint8;
40 
41 
42 template <typename T>
43 inline constexpr int qMetaTypeId();
44 +/
45 
46 struct BuiltinTypeInfo
47 {
48     string typeName;
49     int typeNameID;
50     string realType;
51     string dType;
52 }
53 
54 // F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, RealType)
55 enum immutable(BuiltinTypeInfo[]) primitiveTypes = [
56     BuiltinTypeInfo("Void", 43, "void"),
57     BuiltinTypeInfo("Bool", 1, "bool"),
58     BuiltinTypeInfo("Int", 2, "int"),
59     BuiltinTypeInfo("UInt", 3, "uint"),
60     BuiltinTypeInfo("LongLong", 4, "qlonglong"),
61     BuiltinTypeInfo("ULongLong", 5, "qulonglong"),
62     BuiltinTypeInfo("Double", 6, "double"),
63     BuiltinTypeInfo("Long", 32, "long"),
64     BuiltinTypeInfo("Short", 33, "short"),
65     BuiltinTypeInfo("Char", 34, "char"),
66     BuiltinTypeInfo("Char16", 56, "char16_t", "wchar"),
67     BuiltinTypeInfo("Char32", 57, "char32_t", "dchar"),
68     BuiltinTypeInfo("ULong", 35, "ulong"),
69     BuiltinTypeInfo("UShort", 36, "ushort"),
70     BuiltinTypeInfo("UChar", 37, "uchar"),
71     BuiltinTypeInfo("Float", 38, "float"),
72     BuiltinTypeInfo("SChar", 40, "signed char", "byte"),
73     BuiltinTypeInfo("Nullptr", 51, "std::nullptr_t", "typeof(null)"),
74     BuiltinTypeInfo("QCborSimpleType", 52, "QCborSimpleType"),
75 ];
76 
77 enum immutable(BuiltinTypeInfo[]) primitivePointerTypes = [
78     BuiltinTypeInfo("VoidStar", 31, "void*"),
79 ];
80 
81 /+ #if QT_CONFIG(easingcurve) +/
82 enum immutable(BuiltinTypeInfo[]) easingCurveTypes = [
83     BuiltinTypeInfo("QEasingCurve", 29, "QEasingCurve"),
84 ];
85 /+ #else
86 #define QT_FOR_EACH_STATIC_EASINGCURVE(F)
87 #endif +/
88 
89 /+ #if QT_CONFIG(itemmodel) +/
90 enum immutable(BuiltinTypeInfo[]) itemModelClasses = [
91     BuiltinTypeInfo("QModelIndex", 42, "QModelIndex"),
92     BuiltinTypeInfo("QPersistentModelIndex", 50, "QPersistentModelIndex"),
93 ];
94 /+ #else
95 #define QT_FOR_EACH_STATIC_ITEMMODEL_CLASS(F)
96 #endif +/
97 
98 /+ #if QT_CONFIG(regularexpression) +/
99 enum immutable(BuiltinTypeInfo[]) regularExpressionTypes = [
100     BuiltinTypeInfo("QRegularExpression", 44, "QRegularExpression"),
101 ];
102 /+ #else
103 #  define QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F)
104 #endif +/
105 
106 enum immutable(BuiltinTypeInfo[]) coreClasses = [
107     BuiltinTypeInfo("QChar", 7, "QChar"),
108     BuiltinTypeInfo("QString", 10, "QString"),
109     BuiltinTypeInfo("QByteArray", 12, "QByteArray"),
110     BuiltinTypeInfo("QBitArray", 13, "QBitArray"),
111     BuiltinTypeInfo("QDate", 14, "QDate"),
112     BuiltinTypeInfo("QTime", 15, "QTime"),
113     BuiltinTypeInfo("QDateTime", 16, "QDateTime"),
114     BuiltinTypeInfo("QUrl", 17, "QUrl"),
115     BuiltinTypeInfo("QLocale", 18, "QLocale"),
116     BuiltinTypeInfo("QRect", 19, "QRect"),
117     BuiltinTypeInfo("QRectF", 20, "QRectF"),
118     BuiltinTypeInfo("QSize", 21, "QSize"),
119     BuiltinTypeInfo("QSizeF", 22, "QSizeF"),
120     BuiltinTypeInfo("QLine", 23, "QLine"),
121     BuiltinTypeInfo("QLineF", 24, "QLineF"),
122     BuiltinTypeInfo("QPoint", 25, "QPoint"),
123     BuiltinTypeInfo("QPointF", 26, "QPointF"),
124 ] ~ easingCurveTypes ~ [
125     BuiltinTypeInfo("QUuid", 30, "QUuid"),
126     BuiltinTypeInfo("QVariant", 41, "QVariant"),
127 ] ~ regularExpressionTypes ~ [
128     BuiltinTypeInfo("QJsonValue", 45, "QJsonValue"),
129     BuiltinTypeInfo("QJsonObject", 46, "QJsonObject"),
130     BuiltinTypeInfo("QJsonArray", 47, "QJsonArray"),
131     BuiltinTypeInfo("QJsonDocument", 48, "QJsonDocument"),
132     BuiltinTypeInfo("QCborValue", 53, "QCborValue"),
133     BuiltinTypeInfo("QCborArray", 54, "QCborArray"),
134     BuiltinTypeInfo("QCborMap", 55, "QCborMap"),
135 ] ~ itemModelClasses;
136 
137 enum immutable(BuiltinTypeInfo[]) corePointers = [
138     BuiltinTypeInfo("QObjectStar", 39, "QObject*"),
139 ];
140 
141 enum immutable(BuiltinTypeInfo[]) coreTemplates = [
142     BuiltinTypeInfo("QVariantMap", 8, "QVariantMap"),
143     BuiltinTypeInfo("QVariantList", 9, "QVariantList"),
144     BuiltinTypeInfo("QVariantHash", 28, "QVariantHash"),
145     BuiltinTypeInfo("QVariantPair", 58, "QVariantPair"),
146     BuiltinTypeInfo("QByteArrayList", 49, "QByteArrayList"),
147     BuiltinTypeInfo("QStringList", 11, "QStringList"),
148 ];
149 
150 /+ #if QT_CONFIG(shortcut) +/
151 enum immutable(BuiltinTypeInfo[]) keySequenceClasses = [
152     BuiltinTypeInfo("QKeySequence", 0x100b, "QKeySequence"),
153 ];
154 /+ #else
155 #define QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F)
156 #endif +/
157 
158 enum immutable(BuiltinTypeInfo[]) guiClasses = [
159     BuiltinTypeInfo("QFont", 0x1000, "QFont"),
160     BuiltinTypeInfo("QPixmap", 0x1001, "QPixmap"),
161     BuiltinTypeInfo("QBrush", 0x1002, "QBrush"),
162     BuiltinTypeInfo("QColor", 0x1003, "QColor"),
163     BuiltinTypeInfo("QPalette", 0x1004, "QPalette"),
164     BuiltinTypeInfo("QIcon", 0x1005, "QIcon"),
165     BuiltinTypeInfo("QImage", 0x1006, "QImage"),
166     BuiltinTypeInfo("QPolygon", 0x1007, "QPolygon"),
167     BuiltinTypeInfo("QRegion", 0x1008, "QRegion"),
168     BuiltinTypeInfo("QBitmap", 0x1009, "QBitmap"),
169     BuiltinTypeInfo("QCursor", 0x100a, "QCursor"),
170 ] ~ keySequenceClasses ~ [
171     BuiltinTypeInfo("QPen", 0x100c, "QPen"),
172     BuiltinTypeInfo("QTextLength", 0x100d, "QTextLength"),
173     BuiltinTypeInfo("QTextFormat", 0x100e, "QTextFormat"),
174     BuiltinTypeInfo("QTransform", 0x1010, "QTransform"),
175     BuiltinTypeInfo("QMatrix4x4", 0x1011, "QMatrix4x4"),
176     BuiltinTypeInfo("QVector2D", 0x1012, "QVector2D"),
177     BuiltinTypeInfo("QVector3D", 0x1013, "QVector3D"),
178     BuiltinTypeInfo("QVector4D", 0x1014, "QVector4D"),
179     BuiltinTypeInfo("QQuaternion", 0x1015, "QQuaternion"),
180     BuiltinTypeInfo("QPolygonF", 0x1016, "QPolygonF"),
181     BuiltinTypeInfo("QColorSpace", 0x1017, "QColorSpace"),
182 ];
183 
184 
185 enum immutable(BuiltinTypeInfo[]) widgetClasses = [
186     BuiltinTypeInfo("QSizePolicy", 0x2000, "QSizePolicy"),
187 ];
188 
189 /+
190 // F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, AliasingType, "RealType")
191 #define QT_FOR_EACH_STATIC_ALIAS_TYPE(F)\
192     F(ULong, -1, ulong, "unsigned long") \
193     F(UInt, -1, uint, "unsigned int") \
194     F(UShort, -1, ushort, "unsigned short") \
195     F(UChar, -1, uchar, "unsigned char") \
196     F(LongLong, -1, qlonglong, "long long") \
197     F(ULongLong, -1, qulonglong, "unsigned long long") \
198     F(SChar, -1, signed char, "qint8") \
199     F(UChar, -1, uchar, "quint8") \
200     F(Short, -1, short, "qint16") \
201     F(UShort, -1, ushort, "quint16") \
202     F(Int, -1, int, "qint32") \
203     F(UInt, -1, uint, "quint32") \
204     F(LongLong, -1, qlonglong, "qint64") \
205     F(ULongLong, -1, qulonglong, "quint64") \
206     F(QVariantList, -1, QVariantList, "QList<QVariant>") \
207     F(QVariantMap, -1, QVariantMap, "QMap<QString,QVariant>") \
208     F(QVariantHash, -1, QVariantHash, "QHash<QString,QVariant>") \
209     F(QVariantPair, -1, QVariantPair, "QPair<QVariant,QVariant>") \
210     F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \
211     F(QStringList, -1, QStringList, "QList<QString>") \
212 +/
213 
214 enum immutable(BuiltinTypeInfo[]) allBuiltinTypes =
215     primitiveTypes
216     ~ primitivePointerTypes
217     ~ coreClasses
218     ~ corePointers
219     ~ coreTemplates
220     ~ guiClasses
221     ~ widgetClasses;
222 
223 /+
224 #define QT_DEFINE_METATYPE_ID(TypeName, Id, Name) \
225     TypeName = Id,
226 
227 #define QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(F) \
228     F(QList) \
229     F(QQueue) \
230     F(QStack) \
231     F(QSet) \
232     /*end*/
233 
234 #define QT_FOR_EACH_AUTOMATIC_TEMPLATE_2ARG(F) \
235     F(QHash, class) \
236     F(QMap, class)
237 
238 #define QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(F) \
239     F(QSharedPointer) \
240     F(QWeakPointer) \
241     F(QPointer) +/
242 
243 extern(C++, "QtPrivate")
244 {
245 
246 
247 extern(C++, class) struct QDebug;
248 extern(C++, class) struct QMetaTypeInterface
249 {
250 public:
251     ushort revision; // 0 in Qt 6.0. Can increase if new field are added
252     ushort alignment;
253     uint size;
254     uint flags;
255     /+ mutable +/ QBasicAtomicInt typeId;
256 
257     alias MetaObjectFn = ExternCPPFunc!(const(QMetaObject)* function(const(QMetaTypeInterface)* ));
258     MetaObjectFn metaObjectFn;
259 
260     const(char)* name;
261 
262     alias DefaultCtrFn = ExternCPPFunc!(void function(const(QMetaTypeInterface)* , void* ));
263     DefaultCtrFn defaultCtr;
264     alias CopyCtrFn = ExternCPPFunc!(void function(const(QMetaTypeInterface)* , void* , const(void)* ));
265     CopyCtrFn copyCtr;
266     alias MoveCtrFn = ExternCPPFunc!(void function(const(QMetaTypeInterface)* , void* , void* ));
267     MoveCtrFn moveCtr;
268     alias DtorFn = ExternCPPFunc!(void function(const(QMetaTypeInterface)* , void* ));
269     DtorFn dtor;
270     alias EqualsFn = ExternCPPFunc!(bool function(const(QMetaTypeInterface)* , const(void)* , const(void)* ));
271     EqualsFn equals;
272     alias LessThanFn = ExternCPPFunc!(bool function(const(QMetaTypeInterface)* , const(void)* , const(void)* ));
273     LessThanFn lessThan;
274     alias DebugStreamFn = ExternCPPFunc!(void function(const(QMetaTypeInterface)* , ref QDebug , const(void)* ));
275     DebugStreamFn debugStream;
276     alias DataStreamOutFn = ExternCPPFunc!(void function(const(QMetaTypeInterface)* , ref QDataStream , const(void)* ));
277     DataStreamOutFn dataStreamOut;
278     alias DataStreamInFn = ExternCPPFunc!(void function(const(QMetaTypeInterface)* , ref QDataStream , void* ));
279     DataStreamInFn dataStreamIn;
280 
281     alias LegacyRegisterOp = ExternCPPFunc!(void function());
282     LegacyRegisterOp legacyRegisterOp;
283 }
284 
285 /*!
286     This template is used for implicit conversion from type From to type To.
287     \internal
288 */
289 To convertImplicit(From, To)(ref const(From) from)
290 {
291     return from;
292 }
293 
294     /+ template<typename T, bool>
295     struct AssociativeValueTypeIsMetaType;
296     template<typename T, bool>
297     struct IsMetaTypePair;
298     template<typename, typename>
299     struct MetaTypeSmartPointerHelper; +/
300 
301     struct IsQFlags(T) {
302         /+ std:: +/false_type base0;
303         alias base0 this;
304 }
305 
306     /+ template<typename Enum>
307     struct IsQFlags<QFlags<Enum>> : std::true_type {}; +/
308 
309     struct IsEnumOrFlags(T) {
310         /+ std:: +/disjunction!(/+ std:: +/is_enum!(T), IsQFlags!(T)) base0;
311         alias base0 this;
312 }
313 }  // namespace QtPrivate
314 
315 /// Binding for C++ class [QMetaType](https://doc.qt.io/qt-6/qmetatype.html).
316 extern(C++, class) struct /+ Q_CORE_EXPORT +/ QMetaType {
317 public:
318 /+ #ifndef Q_CLANG_QDOC +/
319     // The code that actually gets compiled.
320     mixin((){
321         import std.conv;
322         string code = "enum Type {";
323         // these are merged with QVariant
324         /+ QT_FOR_EACH_STATIC_TYPE(QT_DEFINE_METATYPE_ID) +/
325         foreach(t; allBuiltinTypes)
326             code ~= text(t.typeName, " = ", t.typeNameID, ", ");
327         code ~= q{
328             FirstCoreType = Type.Bool,
329             LastCoreType = Type.QVariantPair,
330             FirstGuiType = Type.QFont,
331             LastGuiType = Type.QColorSpace,
332             FirstWidgetsType = Type.QSizePolicy,
333             LastWidgetsType = Type.QSizePolicy,
334             HighestInternalId = Type.LastWidgetsType,
335 
336             QReal = qreal.sizeof == double.sizeof ? Type.Double : Type.Float,
337 
338             UnknownType = 0,
339             User = 65536
340         };
341         code ~= "}";
342         return code;
343     }());
344 /+ #else
345     // If we are using QDoc it fakes the Type enum looks like this.
346     enum Type {
347         UnknownType = 0, Bool = 1, Int = 2, UInt = 3, LongLong = 4, ULongLong = 5,
348         Double = 6, Long = 32, Short = 33, Char = 34, ULong = 35, UShort = 36,
349         UChar = 37, Float = 38,
350         VoidStar = 31,
351         QChar = 7, QString = 10, QStringList = 11, QByteArray = 12,
352         QBitArray = 13, QDate = 14, QTime = 15, QDateTime = 16, QUrl = 17,
353         QLocale = 18, QRect = 19, QRectF = 20, QSize = 21, QSizeF = 22,
354         QLine = 23, QLineF = 24, QPoint = 25, QPointF = 26,
355         QEasingCurve = 29, QUuid = 30, QVariant = 41, QModelIndex = 42,
356         QPersistentModelIndex = 50, QRegularExpression = 44,
357         QJsonValue = 45, QJsonObject = 46, QJsonArray = 47, QJsonDocument = 48,
358         QByteArrayList = 49, QObjectStar = 39, SChar = 40,
359         Void = 43,
360         Nullptr = 51,
361         QVariantMap = 8, QVariantList = 9, QVariantHash = 28,
362         QCborSimpleType = 52, QCborValue = 53, QCborArray = 54, QCborMap = 55,
363         Char16 = 56, Char32 = 57,
364 
365         // Gui types
366         QFont = 0x1000, QPixmap = 0x1001, QBrush = 0x1002, QColor = 0x1003, QPalette = 0x1004,
367         QIcon = 0x1005, QImage = 0x1006, QPolygon = 0x1007, QRegion = 0x1008, QBitmap = 0x1009,
368         QCursor = 0x100a, QKeySequence = 0x100b, QPen = 0x100c, QTextLength = 0x100d, QTextFormat = 0x100e,
369         QTransform = 0x1010, QMatrix4x4 = 0x1011, QVector2D = 0x1012,
370         QVector3D = 0x1013, QVector4D = 0x1014, QQuaternion = 0x1015, QPolygonF = 0x1016, QColorSpace = 0x1017,
371 
372         // Widget types
373         QSizePolicy = 0x2000,
374         LastCoreType = Char32,
375         LastGuiType = QColorSpace,
376         User = 65536
377     };
378 #endif +/
379 
380     enum TypeFlag {
381         NeedsConstruction = 0x1,
382         NeedsDestruction = 0x2,
383         RelocatableType = 0x4,
384 /+ #if QT_DEPRECATED_SINCE(6, 0) +/
385         MovableType /+ Q_DECL_ENUMERATOR_DEPRECATED_X("Use RelocatableType instead.") +/ = TypeFlag.RelocatableType,
386 /+ #endif +/
387         PointerToQObject = 0x8,
388         IsEnumeration = 0x10,
389         SharedPointerToQObject = 0x20,
390         WeakPointerToQObject = 0x40,
391         TrackingPointerToQObject = 0x80,
392         IsUnsignedEnumeration = 0x100,
393         IsGadget = 0x200,
394         PointerToGadget = 0x400,
395         IsPointer = 0x800,
396         IsQmlList =0x1000, // used in the QML engine to recognize QQmlListProperty<T> and list<T>
397         IsConst = 0x2000,
398     }
399     /+ Q_DECLARE_FLAGS(TypeFlags, TypeFlag) +/
400 alias TypeFlags = QFlags!(TypeFlag);
401     /+ static void registerNormalizedTypedef(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName, QMetaType type); +/
402 
403 /+ #if QT_DEPRECATED_SINCE(6, 0) +/
404     /+ QT_DEPRECATED_VERSION_6_0 +/
405 /+        static int type(const(char)* typeName)
406     { return QMetaType.fromName(QByteArrayView(typeName)).id(); }
407     /+ QT_DEPRECATED_VERSION_6_0 +/
408         static int type(/+ QT_PREPEND_NAMESPACE(QByteArray) +/ ref const(QByteArray) typeName)
409     { return QMetaType.fromName(QByteArrayView(typeName)).id(); }
410     /+ QT_DEPRECATED_VERSION_6_0 +/
411         static const(char)* typeName(int type)
412     { return QMetaType(type).name(); }
413     /+ QT_DEPRECATED_VERSION_6_0 +/
414         static int sizeOf(int type)
415     { return cast(int)QMetaType(type).sizeOf(); }
416     /+ QT_DEPRECATED_VERSION_6_0 +/
417         static TypeFlags typeFlags(int type)
418     { return QMetaType(type).flags(); }
419     /+ QT_DEPRECATED_VERSION_6_0 +/
420         static const(QMetaObject)* metaObjectForType(int type)
421     { return QMetaType(type).metaObject(); }
422     /+ QT_DEPRECATED_VERSION_6_0
423     static void *create(int type, const void *copy = nullptr)
424     { return QMetaType(type).create(copy); } +/
425     /+ QT_DEPRECATED_VERSION_6_0 +/
426         static void destroy(int type, void* data)
427     { return QMetaType(type).destroy(data); }
428     /+ QT_DEPRECATED_VERSION_6_0 +/
429         static void* construct(int type, void* where, const(void)* copy)
430     { return QMetaType(type).construct(where, copy); }
431     /+ QT_DEPRECATED_VERSION_6_0 +/
432         static void destruct(int type, void* where)
433     { return QMetaType(type).destruct(where); }+/
434 /+ #endif +/
435     static bool isRegistered(int type);
436 
437     /+ explicit +/this(int type);
438     /+ explicit +/ this(const(/+ QtPrivate:: +/QMetaTypeInterface)* d)
439     {
440         this.d_ptr = d;
441     }
442     /+ constexpr QMetaType() = default; +/
443 
444     bool isValid() const;
445     bool isRegistered() const;
446     static if(defined!"QT_QMETATYPE_BC_COMPAT")
447     {
448         int id() const;
449     }
450     else
451     {
452         // ### Qt 7: Remove traces of out of line version
453         // unused int parameter is used to avoid ODR violation
454         int id(int = 0) const
455         {
456             if (d_ptr) {
457                 if (int id = d_ptr.typeId.loadRelaxed())
458                     return id;
459                 return idHelper();
460             }
461             return 0;
462         }/+ ; +/
463     }
464     qsizetype sizeOf() const
465     {
466         return d_ptr ? d_ptr.size : 0;
467     }
468     qsizetype alignOf() const
469     {
470         return d_ptr ? d_ptr.alignment : 0;
471     }
472     TypeFlags flags() const
473     {
474         return d_ptr ? TypeFlags(cast(QFlag)(d_ptr.flags)) : TypeFlags();
475     }
476     const(QMetaObject)* metaObject() const
477     {
478         return d_ptr && d_ptr.metaObjectFn ? d_ptr.metaObjectFn(d_ptr) : null;
479     }
480     const(char)* name() const
481     {
482         return d_ptr ? d_ptr.name : null;
483     }
484 
485     /+ void *create(const void *copy = nullptr) const; +/
486     void destroy(void* data) const;
487     void* construct(void* where, const(void)* copy = null) const;
488     void destruct(void* data) const;
489     QPartialOrdering compare(const(void)* lhs, const(void)* rhs) const;
490     bool equals(const(void)* lhs, const(void)* rhs) const;
491 
492     bool isEqualityComparable() const;
493     bool isOrdered() const;
494 
495 /+ #ifndef QT_NO_DATASTREAM +/
496     version(QT_NO_DATASTREAM){}else
497     {
498         bool save(ref QDataStream stream, const(void)* data) const;
499         bool load(ref QDataStream stream, void* data) const;
500         bool hasRegisteredDataStreamOperators() const;
501 
502     /+ #if QT_DEPRECATED_SINCE(6, 0) +/
503         /+ QT_DEPRECATED_VERSION_6_0 +/
504             static bool save(ref QDataStream stream, int type, const(void)* data)
505         { return QMetaType(type).save(stream, data); }
506         /+ QT_DEPRECATED_VERSION_6_0 +/
507             static bool load(ref QDataStream stream, int type, void* data)
508         { return QMetaType(type).load(stream, data); }
509     }
510 /+ #endif
511 #endif +/
512 
513     static QMetaType fromType(T)()
514     {
515         return QMetaType(qMetaTypeInterfaceForType!(T)());
516     }
517     static QMetaType fromName(QByteArrayView name);
518 
519     /+ friend bool operator==(QMetaType a, QMetaType b)
520     {
521         if (a.d_ptr == b.d_ptr)
522             return true;
523         if (!a.d_ptr || !b.d_ptr)
524             return false; // one type is undefined, the other is defined
525         // avoid id call if we already have the id
526         const int aId = a.id();
527         const int bId = b.id();
528         return aId == bId;
529     } +/
530     /+ friend bool operator!=(QMetaType a, QMetaType b) { return !(a == b); } +/
531 
532 public:
533 
534 /+ #ifndef QT_NO_DEBUG_STREAM
535     bool debugStream(QDebug& dbg, const void *rhs);
536     bool hasRegisteredDebugStreamOperator() const;
537 
538 #if QT_DEPRECATED_SINCE(6, 0)
539     QT_DEPRECATED_VERSION_6_0
540     static bool debugStream(QDebug& dbg, const void *rhs, int typeId)
541     { return QMetaType(typeId).debugStream(dbg, rhs); }
542     template<typename T>
543     QT_DEPRECATED_VERSION_6_0
544     static bool hasRegisteredDebugStreamOperator()
545     { return QMetaType::fromType<T>().hasRegisteredDebugStreamOperator(); }
546     QT_DEPRECATED_VERSION_6_0
547     static bool hasRegisteredDebugStreamOperator(int typeId)
548     { return QMetaType(typeId).hasRegisteredDebugStreamOperator(); }
549 #endif
550 #endif +/
551 
552     // type erased converter function
553 //    alias ConverterFunction = /+ std:: +/function_!(ExternCPPFunc!(bool function(const(void)* src, void* target)));
554 
555     // type erased mutable view, primarily for containers
556 //    alias MutableViewFunction = /+ std:: +/function_!(ExternCPPFunc!(bool function(void* src, void* target)));
557 
558     // implicit conversion supported like double -> float
559     /+ template<typename From, typename To> +/
560     /+ static bool registerConverter()
561     {
562         return registerConverter<From, To>(QtPrivate::convertImplicit<From, To>);
563     } +/
564 
565     // member function as in "QString QFont::toString() const"
566     /+ template<typename From, typename To> +/
567     /+ static bool registerConverter(To(From::*function)() const)
568     {
569         static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
570             "QMetaType::registerConverter: At least one of the types must be a custom type.");
571 
572         const QMetaType fromType = QMetaType::fromType<From>();
573         const QMetaType toType = QMetaType::fromType<To>();
574         auto converter = [function](const void *from, void *to) -> bool {
575             const From *f = static_cast<const From *>(from);
576             To *t = static_cast<To *>(to);
577             *t = (f->*function)();
578             return true;
579         };
580         return registerConverterImpl<From, To>(converter, fromType, toType);
581     } +/
582 
583     // member function
584     /+ template<typename From, typename To> +/
585     /+ static bool registerMutableView(From,To)(ExternCPPFunc!(To function())/+ From::* +/ function_)
586     {
587         static assert((!QMetaTypeId2!(To).IsBuiltIn || !QMetaTypeId2!(From).IsBuiltIn),
588             "QMetaType::registerMutableView: At least one of the types must be a custom type.");
589 
590         const(QMetaType) fromType = QMetaType.fromType!(From)();
591         const(QMetaType) toType = QMetaType.fromType!(To)();
592         auto view = [function](void *from, void *to) -> bool {
593             From* f = static_cast!(From*)(from);
594             To* t = static_cast!(To*)(to);
595             *t = (f->*function_)();
596             return true;
597         };
598         return registerMutableViewImpl!(From, To)(view, fromType, toType);
599     } +/
600 
601     // member function as in "double QString::toDouble(bool *ok = nullptr) const"
602     /+ template<typename From, typename To> +/
603     /+ static bool registerConverter(To(From::*function)(bool*) const)
604     {
605         static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
606             "QMetaType::registerConverter: At least one of the types must be a custom type.");
607 
608         const QMetaType fromType = QMetaType::fromType<From>();
609         const QMetaType toType = QMetaType::fromType<To>();
610         auto converter = [function](const void *from, void *to) -> bool {
611             const From *f = static_cast<const From *>(from);
612             To *t = static_cast<To *>(to);
613             bool result = true;
614             *t = (f->*function)(&result);
615             if (!result)
616                 *t = To();
617             return result;
618         };
619         return registerConverterImpl<From, To>(converter, fromType, toType);
620     } +/
621 
622     // functor or function pointer
623     /+ template<typename From, typename To, typename UnaryFunction> +/
624     /+ static bool registerConverter(UnaryFunction function)
625     {
626         static_assert((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
627             "QMetaType::registerConverter: At least one of the types must be a custom type.");
628 
629         const QMetaType fromType = QMetaType::fromType<From>();
630         const QMetaType toType = QMetaType::fromType<To>();
631         auto converter = [function = std::move(function)](const void *from, void *to) -> bool {
632             const From *f = static_cast<const From *>(from);
633             To *t = static_cast<To *>(to);
634             *t = function(*f);
635             return true;
636         };
637         return registerConverterImpl<From, To>(std::move(converter), fromType, toType);
638     } +/
639 
640     // functor or function pointer
641     /+ template<typename From, typename To, typename UnaryFunction> +/
642     /+ static bool registerMutableView(From,To,UnaryFunction)(UnaryFunction function_)
643     {
644         static assert((!QMetaTypeId2!(To).IsBuiltIn || !QMetaTypeId2!(From).IsBuiltIn),
645             "QMetaType::registerMutableView: At least one of the types must be a custom type.");
646 
647         const(QMetaType) fromType = QMetaType.fromType!(From)();
648         const(QMetaType) toType = QMetaType.fromType!(To)();
649         auto view = [function = /+ std:: +/move(function_)](void *from, void *to) -> bool {
650             From* f = static_cast!(From*)(from);
651             To* t = static_cast!(To*)(to);
652             *t = function_(*f);
653             return true;
654         };
655         return registerMutableViewImpl!(From, To)(/+ std:: +/move(cast(_Tp && )(view)), fromType, toType);
656     } +/
657 
658 private:
659     /+ template<typename From, typename To> +/
660     /+ static bool registerConverterImpl(From,To)(ConverterFunction converter, QMetaType fromType, QMetaType toType)
661     {
662         if (registerConverterFunction(/+ std:: +/move(converter), fromType, toType)) {
663             extern(D) static __gshared const unregister = qScopeGuard([=] {
664                 unregisterConverterFunction(fromType, toType);
665             });
666             return true;
667         } else {
668             return false;
669         }
670     } +/
671 
672     /+ template<typename From, typename To> +/
673     /+ static bool registerMutableViewImpl(From,To)(MutableViewFunction view, QMetaType fromType, QMetaType toType)
674     {
675         if (registerMutableViewFunction(/+ std:: +/move(view), fromType, toType)) {
676             extern(D) static __gshared const unregister = qScopeGuard([=] {
677                unregisterMutableViewFunction(fromType, toType);
678             });
679             return true;
680         } else {
681             return false;
682         }
683     } +/
684 public:
685 
686     static bool convert(QMetaType fromType, const(void)* from, QMetaType toType, void* to);
687     static bool canConvert(QMetaType fromType, QMetaType toType);
688 
689     static bool view(QMetaType fromType, void* from, QMetaType toType, void* to);
690     static bool canView(QMetaType fromType, QMetaType toType);
691 /+ #if QT_DEPRECATED_SINCE(6, 0) +/
692     /+ QT_DEPRECATED_VERSION_6_0 +/
693         static bool convert(const(void)* from, int fromTypeId, void* to, int toTypeId)
694     { return convert(QMetaType(fromTypeId), from, QMetaType(toTypeId), to); }
695     /+ QT_DEPRECATED_VERSION_6_0 +/
696         static bool compare(const(void)* lhs, const(void)* rhs, int typeId, int* result)
697     {
698         auto t = QMetaType(typeId);
699         auto c = t.compare(lhs, rhs);
700         if (c == QPartialOrdering.Unordered) {
701             *result = 0;
702             return false;
703         } else if (c == QPartialOrdering.Less) {
704             *result = -1;
705             return true;
706         } else if (c == QPartialOrdering.Equivalent) {
707             *result = 0;
708             return true;
709         } else {
710             *result = 1;
711             return true;
712         }
713     }
714     /+ QT_DEPRECATED_VERSION_6_0 +/
715         static bool equals(const(void)* lhs, const(void)* rhs, int typeId, int* result)
716     {
717         auto t = QMetaType(typeId);
718         if (!t.isEqualityComparable())
719             return false;
720         *result = t.equals(lhs, rhs) ? 0 : -1;
721         return true;
722     }
723 /+ #endif +/
724 
725     /+ template<typename From, typename To> +/
726     /+ static bool hasRegisteredConverterFunction()
727     {
728         return hasRegisteredConverterFunction(
729                     QMetaType::fromType<From>(), QMetaType::fromType<To>());
730     } +/
731 
732     /+ static bool hasRegisteredConverterFunction(QMetaType fromType, QMetaType toType); +/
733 
734     /+ template<typename From, typename To> +/
735     static bool hasRegisteredMutableViewFunction(From,To)()
736     {
737         return hasRegisteredMutableViewFunction(
738                     QMetaType.fromType!(From)(), QMetaType.fromType!(To)());
739     }
740 
741     static bool hasRegisteredMutableViewFunction(QMetaType fromType, QMetaType toType);
742 
743 /+ #ifndef Q_CLANG_QDOC +/
744     /+ template<typename, bool> +/ /+ friend struct QtPrivate::SequentialValueTypeIsMetaType; +/
745     /+ template<typename, bool> +/ /+ friend struct QtPrivate::AssociativeValueTypeIsMetaType; +/
746     /+ template<typename, bool> +/ /+ friend struct QtPrivate::IsMetaTypePair; +/
747     /+ template<typename, typename> +/ /+ friend struct QtPrivate::MetaTypeSmartPointerHelper; +/
748 /+ #endif +/
749 //    static bool registerConverterFunction(ref const(ConverterFunction) f, QMetaType from, QMetaType to);
750 //    static void unregisterConverterFunction(QMetaType from, QMetaType to);
751 
752 //    static bool registerMutableViewFunction(ref const(MutableViewFunction) f, QMetaType from, QMetaType to);
753  //   static void unregisterMutableViewFunction(QMetaType from, QMetaType to);
754 
755     static void unregisterMetaType(QMetaType type);
756     const(/+ QtPrivate:: +/QMetaTypeInterface)* iface() { return d_ptr; }
757 
758 package:
759     mixin(changeWindowsMangling(q{mangleChangeAccess("private")}, q{
760     int idHelper() const;
761     }));
762     /+ friend class QVariant; +/
763     const(/+ QtPrivate:: +/QMetaTypeInterface)* d_ptr = null;
764     mixin(CREATE_CONVENIENCE_WRAPPERS);
765 }
766 
767 /+ #undef QT_DEFINE_METATYPE_ID +/
768 /+pragma(inline, true) QFlags!(QMetaType.TypeFlags.enum_type) operator |(QMetaType.TypeFlags.enum_type f1, QMetaType.TypeFlags.enum_type f2)/+noexcept+/{return QFlags!(QMetaType.TypeFlags.enum_type)(f1)|f2;}+/
769 /+pragma(inline, true) QFlags!(QMetaType.TypeFlags.enum_type) operator |(QMetaType.TypeFlags.enum_type f1, QFlags!(QMetaType.TypeFlags.enum_type) f2)/+noexcept+/{return f2|f1;}+/
770 /+pragma(inline, true) QFlags!(QMetaType.TypeFlags.enum_type) operator &(QMetaType.TypeFlags.enum_type f1, QMetaType.TypeFlags.enum_type f2)/+noexcept+/{return QFlags!(QMetaType.TypeFlags.enum_type)(f1)&f2;}+/
771 /+pragma(inline, true) QFlags!(QMetaType.TypeFlags.enum_type) operator &(QMetaType.TypeFlags.enum_type f1, QFlags!(QMetaType.TypeFlags.enum_type) f2)/+noexcept+/{return f2&f1;}+/
772 /+pragma(inline, true) void operator +(QMetaType.TypeFlags.enum_type f1, QMetaType.TypeFlags.enum_type f2)/+noexcept+/;+/
773 /+pragma(inline, true) void operator +(QMetaType.TypeFlags.enum_type f1, QFlags!(QMetaType.TypeFlags.enum_type) f2)/+noexcept+/;+/
774 /+pragma(inline, true) void operator +(int f1, QFlags!(QMetaType.TypeFlags.enum_type) f2)/+noexcept+/;+/
775 /+pragma(inline, true) void operator -(QMetaType.TypeFlags.enum_type f1, QMetaType.TypeFlags.enum_type f2)/+noexcept+/;+/
776 /+pragma(inline, true) void operator -(QMetaType.TypeFlags.enum_type f1, QFlags!(QMetaType.TypeFlags.enum_type) f2)/+noexcept+/;+/
777 /+pragma(inline, true) void operator -(int f1, QFlags!(QMetaType.TypeFlags.enum_type) f2)/+noexcept+/;+/
778 /+pragma(inline, true) QIncompatibleFlag operator |(QMetaType.TypeFlags.enum_type f1, int f2)/+noexcept+/{return QIncompatibleFlag(int(f1)|f2);}+/
779 /+pragma(inline, true) void operator +(int f1, QMetaType.TypeFlags.enum_type f2)/+noexcept+/;+/
780 /+pragma(inline, true) void operator +(QMetaType.TypeFlags.enum_type f1, int f2)/+noexcept+/;+/
781 /+pragma(inline, true) void operator -(int f1, QMetaType.TypeFlags.enum_type f2)/+noexcept+/;+/
782 /+pragma(inline, true) void operator -(QMetaType.TypeFlags.enum_type f1, int f2)/+noexcept+/;+/
783 
784 /+ Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaType::TypeFlags)
785 #define QT_METATYPE_PRIVATE_DECLARE_TYPEINFO(C, F)  \
786     }                                               \
787     Q_DECLARE_TYPEINFO(QtMetaTypePrivate:: C, (F)); \
788     namespace QtMetaTypePrivate {
789 
790 
791 namespace QtMetaTypePrivate {
792 
793 
794 class QPairVariantInterfaceImpl
795 {
796 public:
797     const void *_pair;
798     QMetaType _metaType_first;
799     QMetaType _metaType_second;
800 
801     typedef void (*getFunc)(const void * const *p, void *);
802 
803     getFunc _getFirst;
804     getFunc _getSecond;
805 
806     template<class T>
807     static void getFirstImpl(const void * const *pair, void *dataPtr)
808     { *static_cast<typename T::first_type *>(dataPtr) = static_cast<const T*>(*pair)->first; }
809     template<class T>
810     static void getSecondImpl(const void * const *pair, void *dataPtr)
811     { *static_cast<typename T::second_type *>(dataPtr) = static_cast<const T*>(*pair)->second; }
812 
813 public:
814     template<class T> QPairVariantInterfaceImpl(const T*p)
815       : _pair(p)
816       , _metaType_first(QMetaType::fromType<typename T::first_type>())
817       , _metaType_second(QMetaType::fromType<typename T::second_type>())
818       , _getFirst(getFirstImpl<T>)
819       , _getSecond(getSecondImpl<T>)
820     {
821     }
822 
823     constexpr QPairVariantInterfaceImpl()
824       : _pair(nullptr)
825       , _getFirst(nullptr)
826       , _getSecond(nullptr)
827     {
828     }
829 
830     inline void first(void *dataPtr) const { _getFirst(&_pair, dataPtr); }
831     inline void second(void *dataPtr) const { _getSecond(&_pair, dataPtr); }
832 };
833 QT_METATYPE_PRIVATE_DECLARE_TYPEINFO(QPairVariantInterfaceImpl, Q_RELOCATABLE_TYPE)
834 template<typename From>
835 struct QPairVariantInterfaceConvertFunctor;
836 
837 template<typename T, typename U>
838 struct QPairVariantInterfaceConvertFunctor<std::pair<T, U> >
839 {
840     QPairVariantInterfaceImpl operator()(const std::pair<T, U>& f) const
841 ==== BASE ====
842     {
843         return QPairVariantInterfaceImpl(&f);
844     }
845 };
846 
847 }
848 
849 
850 #define QT_FORWARD_DECLARE_SHARED_POINTER_TYPES_ITER(Name) \
851     template <class T> class Name; \
852 
853 
854 QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(QT_FORWARD_DECLARE_SHARED_POINTER_TYPES_ITER) +/
855 extern(C++, "QtPrivate")
856 {
857     struct IsPointerToTypeDerivedFromQObject(T)
858     {
859         enum { Value = false }
860     }
861 
862     // Specialize to avoid sizeof(void) warning
863     /+ template<>
864     struct IsPointerToTypeDerivedFromQObject<void*>
865     {
866         enum { Value = false };
867     };
868     template<>
869     struct IsPointerToTypeDerivedFromQObject<const void*>
870     {
871         enum { Value = false };
872     };
873     template<>
874     struct IsPointerToTypeDerivedFromQObject<QObject*>
875     {
876         enum { Value = true };
877     };
878 
879     template<typename T>
880     struct IsPointerToTypeDerivedFromQObject<T*>
881     {
882         typedef qint8 yes_type;
883         typedef qint64 no_type;
884 
885 #ifndef QT_NO_QOBJECT
886         static yes_type checkType(QObject* );
887         static yes_type checkType(const QObject* );
888 #endif
889         static no_type checkType(...);
890         static_assert(sizeof(T), "Type argument of Q_PROPERTY or Q_DECLARE_METATYPE(T*) must be fully defined");
891         enum { Value = sizeof(checkType(static_cast<T*>(nullptr))) == sizeof(yes_type) };
892     }; +/
893 
894     struct IsGadgetHelper(T, Enable) { enum { IsRealGadget = false, IsGadgetOrDerivedFrom = false } }
895 
896     /+ template<typename T>
897     struct IsGadgetHelper<T, typename T::QtGadgetHelper>
898     {
899         template <typename X>
900         static char checkType(void (X::*)());
901         static void *checkType(void (T::*)());
902         enum {
903             IsRealGadget = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *),
904             IsGadgetOrDerivedFrom = true
905         };
906     }; +/
907 
908     struct IsPointerToGadgetHelper(T, Enable) { enum { IsRealGadget = false, IsGadgetOrDerivedFrom = false } }
909 
910     /+ template<typename T>
911     struct IsPointerToGadgetHelper<T*, typename T::QtGadgetHelper>
912     {
913         using BaseType = T;
914         template <typename X>
915         static char checkType(void (X::*)());
916         static void *checkType(void (T::*)());
917         enum {
918             IsRealGadget = !IsPointerToTypeDerivedFromQObject<T*>::Value && sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *),
919             IsGadgetOrDerivedFrom = !IsPointerToTypeDerivedFromQObject<T*>::Value
920         };
921     };
922 
923 
924     template<typename T> char qt_getEnumMetaObject(const T&); +/
925 
926     struct IsQEnumHelper(T) {
927         static ref const(T) declval();
928         // If the type was declared with Q_ENUM, the friend qt_getEnumMetaObject() declared in the
929         // Q_ENUM macro will be chosen by ADL, and the return type will be QMetaObject*.
930         // Otherwise the chosen overload will be the catch all template function
931         // qt_getEnumMetaObject(T) which returns 'char'
932         enum { Value = (qt_getEnumMetaObject(declval())). sizeof == (QMetaObject*).sizeof }
933     }
934     /+ template<> struct IsQEnumHelper<void> { enum { Value = false }; };
935 
936     template<typename T, typename Enable = void>
937     struct MetaObjectForType
938     {
939         static constexpr const QMetaObject *value() { return nullptr; }
940         using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *);
941         static constexpr MetaObjectFn metaObjectFunction = nullptr;
942     };
943 #ifndef QT_NO_QOBJECT
944     template<>
945     struct MetaObjectForType<void>
946     {
947         static constexpr const QMetaObject *value() { return nullptr; }
948         using MetaObjectFn = const QMetaObject *(*)(const QMetaTypeInterface *);
949         static constexpr MetaObjectFn metaObjectFunction = nullptr;
950     };
951     template<typename T>
952     struct MetaObjectForType<T*, typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type>
953     {
954         static constexpr const QMetaObject *value() { return &T::staticMetaObject; }
955         static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return &T::staticMetaObject; }
956     };
957     template<typename T>
958     struct MetaObjectForType<T, typename std::enable_if<IsGadgetHelper<T>::IsGadgetOrDerivedFrom>::type>
959     {
960         static constexpr const QMetaObject *value() { return &T::staticMetaObject; }
961         static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return &T::staticMetaObject; }
962     };
963     template<typename T>
964     struct MetaObjectForType<T, typename std::enable_if<IsPointerToGadgetHelper<T>::IsGadgetOrDerivedFrom>::type>
965     {
966         static constexpr const QMetaObject *value()
967         {
968             return &IsPointerToGadgetHelper<T>::BaseType::staticMetaObject;
969         }
970         static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return value(); }
971     };
972     template<typename T>
973     struct MetaObjectForType<T, typename std::enable_if<IsQEnumHelper<T>::Value>::type >
974     {
975         static constexpr const QMetaObject *value() { return qt_getEnumMetaObject(T()); }
976         static constexpr const QMetaObject *metaObjectFunction(const QMetaTypeInterface *) { return value(); }
977     };
978 #endif +/
979     template MetaObjectForType(T)
980     {
981         static if(is(const(T): const(QObject)))
982         {
983             static const(QMetaObject)* value() { return &T.staticMetaObject; }
984             static const(QMetaObject)* metaObjectFunction(const(QMetaTypeInterface)*) { return &T.staticMetaObject; }
985         }
986         else
987         {
988             static const(QMetaObject)* value() { return null; }
989             alias MetaObjectFn = const(QMetaObject)* function(const(QMetaTypeInterface)*);
990             extern(D) static immutable MetaObjectFn metaObjectFunction = null;
991         }
992     }
993 
994     struct IsSharedPointerToTypeDerivedFromQObject(T)
995     {
996         enum { Value = false }
997     }
998 
999     /+ template<typename T>
1000     struct IsSharedPointerToTypeDerivedFromQObject<QSharedPointer<T> > : IsPointerToTypeDerivedFromQObject<T*>
1001     {
1002     }; +/
1003 
1004     struct IsWeakPointerToTypeDerivedFromQObject(T)
1005     {
1006         enum { Value = false }
1007     }
1008 
1009     /+ template<typename T>
1010     struct IsWeakPointerToTypeDerivedFromQObject<QWeakPointer<T> > : IsPointerToTypeDerivedFromQObject<T*>
1011     {
1012     }; +/
1013 
1014     struct IsTrackingPointerToTypeDerivedFromQObject(T)
1015     {
1016         enum { Value = false }
1017     }
1018 
1019     /+ template<typename T>
1020     struct IsTrackingPointerToTypeDerivedFromQObject<QPointer<T> >
1021     {
1022         enum { Value = true };
1023     };
1024 
1025     template<typename T>
1026     struct IsSequentialContainer
1027     {
1028         enum { Value = false };
1029     };
1030 
1031     template<typename T>
1032     struct IsAssociativeContainer
1033     {
1034         enum { Value = false };
1035     }; +/
1036 
1037     struct SequentialContainerTransformationHelper(T, /+ bool +/ /+ = QtPrivate::IsSequentialContainer<T>::Value +/)
1038     {
1039         /+ static bool registerConverter()
1040         {
1041             return false;
1042         } +/
1043 
1044         static bool registerMutableView()
1045         {
1046             return false;
1047         }
1048     }
1049 
1050     struct SequentialValueTypeIsMetaType(T, /+ bool +/ /+ = QMetaTypeId2<typename T::value_type>::Defined +/)
1051     {
1052         /+ static bool registerConverter()
1053         {
1054             return false;
1055         } +/
1056 
1057         static bool registerMutableView()
1058         {
1059             return false;
1060         }
1061     }
1062 
1063     /+ template<typename T>
1064     struct SequentialContainerTransformationHelper<T, true> : SequentialValueTypeIsMetaType<T>
1065     {
1066     }; +/
1067 
1068     struct AssociativeContainerTransformationHelper(T, /+ bool +/ /+ = QtPrivate::IsAssociativeContainer<T>::Value +/)
1069     {
1070         /+ static bool registerConverter()
1071         {
1072             return false;
1073         } +/
1074 
1075         static bool registerMutableView()
1076         {
1077             return false;
1078         }
1079     }
1080 
1081     struct AssociativeKeyTypeIsMetaType(T, /+ bool +/ /+ = QMetaTypeId2<typename T::key_type>::Defined +/)
1082     {
1083         /+ static bool registerConverter()
1084         {
1085             return false;
1086         } +/
1087 
1088         static bool registerMutableView()
1089         {
1090             return false;
1091         }
1092     }
1093 
1094     struct AssociativeMappedTypeIsMetaType(T, /+ bool +/ /+ = QMetaTypeId2<typename T::mapped_type>::Defined +/)
1095     {
1096         /+ static bool registerConverter()
1097         {
1098             return false;
1099         } +/
1100 
1101         static bool registerMutableView()
1102         {
1103             return false;
1104         }
1105     }
1106 
1107     /+ template<typename T>
1108     struct AssociativeContainerTransformationHelper<T, true> : AssociativeKeyTypeIsMetaType<T>
1109     {
1110     };
1111 
1112     template<typename T, bool = QMetaTypeId2<typename T::first_type>::Defined
1113                                 && QMetaTypeId2<typename T::second_type>::Defined>
1114     struct IsMetaTypePair
1115     {
1116         static bool registerConverter()
1117         {
1118             return false;
1119         }
1120     };
1121 
1122     template<typename T>
1123     struct IsMetaTypePair<T, true>
1124     {
1125         inline static bool registerConverter();
1126     };
1127 
1128     template<typename T>
1129     struct IsPair
1130     {
1131         static bool registerConverter()
1132         {
1133             return false;
1134         }
1135     };
1136     template<typename T, typename U>
1137     struct IsPair<std::pair<T, U> > : IsMetaTypePair<std::pair<T, U> > {};
1138 
1139     template<typename T>
1140     struct MetaTypePairHelper : IsPair<T> {};
1141 
1142     template<typename T, typename = void>
1143     struct MetaTypeSmartPointerHelper
1144     {
1145         static bool registerConverter() { return false; }
1146     };
1147 
1148     Q_CORE_EXPORT bool isBuiltinType(const QByteArray &type); +/
1149 } // namespace QtPrivate
1150 
1151 struct QMetaTypeIdQObject(T, /+ int +/ /+ =
1152     QtPrivate::IsPointerToTypeDerivedFromQObject<T>::Value ? QMetaType::PointerToQObject :
1153     QtPrivate::IsGadgetHelper<T>::IsRealGadget             ? QMetaType::IsGadget :
1154     QtPrivate::IsPointerToGadgetHelper<T>::IsRealGadget    ? QMetaType::PointerToGadget :
1155     QtPrivate::IsQEnumHelper<T>::Value                     ? QMetaType::IsEnumeration : 0 +/)
1156 {
1157     enum {
1158         Defined = 0
1159     }
1160 }
1161 
1162 alias QMetaTypeId(T) = QMetaTypeIdQObject!(T);
1163 
1164 mixin((){
1165     import std.conv;
1166     string code = "template QMetaTypeId2(T)\n";
1167     code ~= "{\n";
1168     code ~= "    static if(std.traits.isBuiltinType!T)\n";
1169     code ~= "    {\n";
1170     bool needsElse = false;
1171     foreach(i, t; allBuiltinTypes)
1172     {
1173         string realType2 = t.realType;
1174         if(t.dType.length)
1175             realType2 = t.dType;
1176         if(realType2[0] != 'Q')
1177         {
1178             code ~= "        ";
1179             if(needsElse)
1180                 code ~= "else ";
1181             code ~= text("static if(is(T == ", realType2, "))\n");
1182             code ~= "        {\n";
1183             code ~= text("            enum { Defined = 1, IsBuiltIn = true, MetaType = ", t.typeNameID, " };\n");
1184             code ~= text("            pragma(inline, true) static int qt_metatype_id() { return ", t.typeNameID, "; }\n");
1185             code ~= text("            extern(D) static immutable(char[", t.realType.length, " + 1]) nameAsArray = \"", t.realType, "\";\n");
1186             code ~= "        }\n";
1187             needsElse = true;
1188         }
1189     }
1190     code ~= "        else\n";
1191     code ~= "        {\n";
1192     code ~= "            static assert(false, \"type not supported \" ~ T.stringof);\n";
1193     code ~= "        }\n";
1194     code ~= "    }\n";
1195     code ~= "    else\n";
1196     code ~= "    {\n";
1197     needsElse = false;
1198     code ~= "        static if(IsInQtPackage!T)\n";
1199     code ~= "        {\n";
1200     foreach(i, t; allBuiltinTypes)
1201     {
1202         string realType2 = t.realType;
1203         if(t.dType.length)
1204             realType2 = t.dType;
1205         if(realType2[0] == 'Q')
1206         {
1207             code ~= "            ";
1208             if(needsElse)
1209                 code ~= "else ";
1210             // TODO: Match templates like QList!(QString)
1211             code ~= text("static if(__traits(identifier, T) == \"", realType2, "\")\n");
1212             code ~= "            {\n";
1213             code ~= text("                enum { Defined = 1, IsBuiltIn = true, MetaType = ", t.typeNameID, " };\n");
1214             code ~= text("                pragma(inline, true) static int qt_metatype_id() { return ", t.typeNameID, "; }\n");
1215             code ~= text("                extern(D) static immutable(char[", t.realType.length, " + 1]) nameAsArray = \"", t.realType, "\";\n");
1216             code ~= "            }\n";
1217             needsElse = true;
1218         }
1219     }
1220     code ~= "            else\n";
1221     code ~= "            {\n";
1222     code ~= "                enum { Defined = QMetaTypeId!(T).Defined, IsBuiltIn=false }\n";
1223     code ~= "                pragma(inline, true) static int qt_metatype_id() { return QMetaTypeId!(T).qt_metatype_id(); }\n";
1224     code ~= "            }\n";
1225     code ~= "        }\n";
1226     code ~= "        else\n";
1227     code ~= "        {\n";
1228     code ~= "            enum { Defined = QMetaTypeId!(T).Defined, IsBuiltIn=false }\n";
1229     code ~= "            pragma(inline, true) static int qt_metatype_id() { return QMetaTypeId!(T).qt_metatype_id(); }\n";
1230     code ~= "        }\n";
1231     code ~= "    }\n";
1232     code ~= "}\n";
1233     return code;
1234 }());
1235 
1236 /+ template <typename T>
1237 struct QMetaTypeId2<const T&> : QMetaTypeId2<T> {};
1238 
1239 template <typename T>
1240 struct QMetaTypeId2<T&> { enum {Defined = false }; }; +/
1241 
1242 extern(C++, "QtPrivate") {
1243     struct QMetaTypeIdHelper(T, bool Defined=QMetaTypeId2!(T).Defined) {
1244         pragma(inline, true) static int qt_metatype_id()
1245         { return QMetaTypeId2!(T).qt_metatype_id(); }
1246     }
1247     /+ template <typename T> struct QMetaTypeIdHelper<T, false> {
1248         static inline constexpr int qt_metatype_id()
1249         { return -1; }
1250     };
1251 
1252     // Function pointers don't derive from QObject
1253     template <typename Result, typename... Args>
1254     struct IsPointerToTypeDerivedFromQObject<Result(*)(Args...)> { enum { Value = false }; };
1255 
1256     template<typename T>
1257     inline constexpr bool IsQmlListType = false;
1258 
1259     template<typename T, bool = std::is_enum<T>::value>
1260     constexpr bool IsUnsignedEnum = false;
1261     template<typename T>
1262     constexpr bool IsUnsignedEnum<T, true> = !std::is_signed_v<std::underlying_type_t<T>>; +/
1263 
1264     private template RemovePointer(T)
1265     {
1266         static if(is(T == X*, X))
1267             alias RemovePointer = typeof(*T.init);
1268         else
1269             alias RemovePointer = T;
1270     }
1271 
1272     struct QMetaTypeTypeFlags(T)
1273     {
1274         enum { Flags = (QTypeInfo!(T).isRelocatable ? QMetaType.TypeFlag.RelocatableType : 0)
1275                      | (QTypeInfo!(T).isComplex ? QMetaType.TypeFlag.NeedsConstruction : 0)
1276                      | (QTypeInfo!(T).isComplex ? QMetaType.TypeFlag.NeedsDestruction : 0)
1277                      // TODO
1278                      /*| (IsPointerToTypeDerivedFromQObject!(T).Value ? QMetaType.TypeFlag.PointerToQObject : 0)
1279                      | (IsSharedPointerToTypeDerivedFromQObject!(T).Value ? QMetaType.TypeFlag.SharedPointerToQObject : 0)
1280                      | (IsWeakPointerToTypeDerivedFromQObject!(T).Value ? QMetaType.TypeFlag.WeakPointerToQObject : 0)
1281                      | (IsTrackingPointerToTypeDerivedFromQObject!(T).Value ? QMetaType.TypeFlag.TrackingPointerToQObject : 0)
1282                      | (IsEnumOrFlags!(T).value ? QMetaType.TypeFlag.IsEnumeration : 0)
1283                      | (IsGadgetHelper!(T).IsGadgetOrDerivedFrom ? QMetaType.TypeFlag.IsGadget : 0)
1284                      | (IsPointerToGadgetHelper!(T).IsGadgetOrDerivedFrom ? QMetaType.TypeFlag.PointerToGadget : 0)*/
1285                      | (QTypeInfo!(T).isPointer ? QMetaType.TypeFlag.IsPointer : 0)
1286                      //| (IsUnsignedEnum!(T) ? QMetaType.TypeFlag.IsUnsignedEnumeration : 0)
1287                      //| (IsQmlListType!(T) ? QMetaType.TypeFlag.IsQmlList : 0)
1288                      | (is(RemovePointer!(T) == const) ? QMetaType.TypeFlag.IsConst : 0)
1289              };
1290     };
1291 
1292     struct MetaTypeDefinedHelper(T, bool defined)
1293     {
1294         enum DefinedType { Defined = defined }
1295     }
1296 
1297     struct QSmartPointerConvertFunctor(SmartPointer)
1298     {
1299         /+QObject operator ()(ref const(SmartPointer) p) const
1300         {
1301             return p.operator->();
1302         }+/
1303     }
1304 
1305     // hack to delay name lookup to instantiation time by making
1306     // EnableInternalData a dependent name:
1307 
1308     /+ template<typename T>
1309     struct QSmartPointerConvertFunctor<QWeakPointer<T> >
1310     {
1311         QObject* operator()(const QWeakPointer<T> &p) const
1312         {
1313             return QtPrivate::EnableInternalDataWrap<T>::internalData(p);
1314         }
1315     }; +/
1316 
1317 }
1318 
1319 /+ template <typename T>
1320 int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normalizedTypeName)
1321 {
1322 #ifndef QT_NO_QOBJECT
1323     Q_ASSERT_X(normalizedTypeName == QMetaObject::normalizedType(normalizedTypeName.constData()),
1324                "qRegisterNormalizedMetaType",
1325                "qRegisterNormalizedMetaType was called with a not normalized type name, "
1326                "please call qRegisterMetaType instead.");
1327 #endif
1328 
1329     const QMetaType metaType = QMetaType::fromType<T>();
1330     const int id = metaType.id();
1331 
1332     QtPrivate::SequentialContainerTransformationHelper<T>::registerConverter();
1333     QtPrivate::SequentialContainerTransformationHelper<T>::registerMutableView();
1334     QtPrivate::AssociativeContainerTransformationHelper<T>::registerConverter();
1335     QtPrivate::AssociativeContainerTransformationHelper<T>::registerMutableView();
1336     QtPrivate::MetaTypePairHelper<T>::registerConverter();
1337     QtPrivate::MetaTypeSmartPointerHelper<T>::registerConverter();
1338 
1339     if (normalizedTypeName != metaType.name())
1340         QMetaType::registerNormalizedTypedef(normalizedTypeName, metaType);
1341 
1342     return id;
1343 } +/
1344 
1345 int qRegisterMetaType(T)(const(char)* typeName)
1346 {
1347 /+ #ifdef QT_NO_QOBJECT
1348     QT_PREPEND_NAMESPACE(QByteArray) normalizedTypeName = typeName;
1349 #else +/
1350     /+ QT_PREPEND_NAMESPACE(QByteArray) +/QByteArray normalizedTypeName = QMetaObject.normalizedType(typeName);
1351 /+ #endif +/
1352     return qRegisterNormalizedMetaType!(T)(normalizedTypeName);
1353 }
1354 
1355 pragma(inline, true) int qMetaTypeId(T)()
1356 {
1357     static if (cast(bool)(QMetaTypeId2!(T).IsBuiltIn)) {
1358         return QMetaTypeId2!(T).MetaType;
1359     } else {
1360         return QMetaType.fromType!(T)().id();
1361     }
1362 }
1363 
1364 pragma(inline, true) int qRegisterMetaType(T)()
1365 {
1366     int id = qMetaTypeId!(T)();
1367     return id;
1368 }
1369 
1370 /+ #ifndef QT_NO_QOBJECT
1371 template <typename T>
1372 struct QMetaTypeIdQObject<T*, QMetaType::PointerToQObject>
1373 {
1374     enum {
1375         Defined = 1
1376     };
1377 
1378     static int qt_metatype_id()
1379     {
1380         static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
1381         if (const int id = metatype_id.loadAcquire())
1382             return id;
1383         const char *const cName = T::staticMetaObject.className();
1384         QByteArray typeName;
1385         typeName.reserve(strlen(cName) + 1);
1386         typeName.append(cName).append('*');
1387         const int newId = qRegisterNormalizedMetaType<T *>(typeName);
1388         metatype_id.storeRelease(newId);
1389         return newId;
1390     }
1391 };
1392 
1393 template <typename T>
1394 struct QMetaTypeIdQObject<T, QMetaType::IsGadget>
1395 {
1396     enum {
1397         Defined = std::is_default_constructible<T>::value
1398     };
1399 
1400     static int qt_metatype_id()
1401     {
1402         static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
1403         if (const int id = metatype_id.loadAcquire())
1404             return id;
1405         const char *const cName = T::staticMetaObject.className();
1406         const int newId = qRegisterNormalizedMetaType<T>(cName);
1407         metatype_id.storeRelease(newId);
1408         return newId;
1409     }
1410 };
1411 
1412 template <typename T>
1413 struct QMetaTypeIdQObject<T*, QMetaType::PointerToGadget>
1414 {
1415     enum {
1416         Defined = 1
1417     };
1418 
1419     static int qt_metatype_id()
1420     {
1421         static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
1422         if (const int id = metatype_id.loadAcquire())
1423             return id;
1424         const char *const cName = T::staticMetaObject.className();
1425         QByteArray typeName;
1426         typeName.reserve(strlen(cName) + 1);
1427         typeName.append(cName).append('*');
1428         const int newId = qRegisterNormalizedMetaType<T *>(typeName);
1429         metatype_id.storeRelease(newId);
1430         return newId;
1431     }
1432 };
1433 
1434 template <typename T>
1435 struct QMetaTypeIdQObject<T, QMetaType::IsEnumeration>
1436 {
1437     enum {
1438         Defined = 1
1439     };
1440 
1441     static int qt_metatype_id()
1442     {
1443         static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
1444         if (const int id = metatype_id.loadAcquire())
1445             return id;
1446         const char *eName = qt_getEnumName(T());
1447         const char *cName = qt_getEnumMetaObject(T())->className();
1448         QByteArray typeName;
1449         typeName.reserve(strlen(cName) + 2 + strlen(eName));
1450         typeName.append(cName).append("::").append(eName);
1451         const int newId = qRegisterNormalizedMetaType<T>(typeName);
1452         metatype_id.storeRelease(newId);
1453         return newId;
1454     }
1455 };
1456 #endif
1457 
1458 #define Q_DECLARE_OPAQUE_POINTER(POINTER)                               \
1459     QT_BEGIN_NAMESPACE namespace QtPrivate {                            \
1460         template <>                                                     \
1461         struct IsPointerToTypeDerivedFromQObject<POINTER >              \
1462         {                                                               \
1463             enum { Value = false };                                     \
1464         };                                                              \
1465     } QT_END_NAMESPACE                                                  \
1466     /**/
1467 
1468 #ifndef Q_MOC_RUN
1469 #define Q_DECLARE_METATYPE(TYPE) Q_DECLARE_METATYPE_IMPL(TYPE)
1470 #define Q_DECLARE_METATYPE_IMPL(TYPE)                                   \
1471     QT_BEGIN_NAMESPACE                                                  \
1472     template <>                                                         \
1473     struct QMetaTypeId< TYPE >                                          \
1474     {                                                                   \
1475         enum { Defined = 1 };                                           \
1476         static int qt_metatype_id()                                     \
1477             {                                                           \
1478                 static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
1479                 if (const int id = metatype_id.loadAcquire())           \
1480                     return id;                                          \
1481                 constexpr auto arr = QtPrivate::typenameHelper<TYPE>(); \
1482                 auto name = arr.data();                                 \
1483                 if (QByteArrayView(name) == (#TYPE)) {                  \
1484                     const int id = qRegisterNormalizedMetaType<TYPE>(name); \
1485                     metatype_id.storeRelease(id);                       \
1486                     return id;                                          \
1487                 }                                                       \
1488                 const int newId = qRegisterMetaType< TYPE >(#TYPE);     \
1489                 metatype_id.storeRelease(newId);                        \
1490                 return newId;                                           \
1491             }                                                           \
1492     };                                                                  \
1493     QT_END_NAMESPACE
1494 #endif // Q_MOC_RUN
1495 
1496 #define Q_DECLARE_BUILTIN_METATYPE(TYPE, METATYPEID, NAME) \
1497     QT_BEGIN_NAMESPACE \
1498     template<> struct QMetaTypeId2<NAME> \
1499     { \
1500         using NameAsArrayType = std::array<char, sizeof(#NAME)>; \
1501         enum { Defined = 1, IsBuiltIn = true, MetaType = METATYPEID };   \
1502         static inline constexpr int qt_metatype_id() { return METATYPEID; } \
1503         static constexpr NameAsArrayType nameAsArray = { #NAME }; \
1504     }; \
1505     QT_END_NAMESPACE
1506 
1507 #define QT_FORWARD_DECLARE_STATIC_TYPES_ITER(TypeName, TypeId, Name) \
1508     class Name;
1509 
1510 
1511 QT_FOR_EACH_STATIC_CORE_CLASS(QT_FORWARD_DECLARE_STATIC_TYPES_ITER) +/
1512 extern(C++, class) struct QMatrix4x4;
1513 extern(C++, class) struct QQuaternion;
1514 /+ QT_FOR_EACH_STATIC_GUI_CLASS(QT_FORWARD_DECLARE_STATIC_TYPES_ITER)
1515 QT_FOR_EACH_STATIC_WIDGETS_CLASS(QT_FORWARD_DECLARE_STATIC_TYPES_ITER)
1516 #undef QT_FORWARD_DECLARE_STATIC_TYPES_ITER
1517 
1518 #define Q_DECLARE_METATYPE_TEMPLATE_1ARG(SINGLE_ARG_TEMPLATE) \
1519 QT_BEGIN_NAMESPACE \
1520 template <typename T> \
1521 struct QMetaTypeId< SINGLE_ARG_TEMPLATE<T> > \
1522 { \
1523     enum { \
1524         Defined = QMetaTypeId2<T>::Defined \
1525     }; \
1526     static int qt_metatype_id() \
1527     { \
1528         static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
1529         if (const int id = metatype_id.loadRelaxed()) \
1530             return id; \
1531         const char *tName = QMetaType::fromType<T>().name(); \
1532         Q_ASSERT(tName); \
1533         const size_t tNameLen = qstrlen(tName); \
1534         QByteArray typeName; \
1535         typeName.reserve(sizeof(#SINGLE_ARG_TEMPLATE) + 1 + tNameLen + 1 + 1); \
1536         typeName.append(#SINGLE_ARG_TEMPLATE, int(sizeof(#SINGLE_ARG_TEMPLATE)) - 1) \
1537             .append('<').append(tName, tNameLen); \
1538         typeName.append('>'); \
1539         const int newId = qRegisterNormalizedMetaType< SINGLE_ARG_TEMPLATE<T> >(typeName); \
1540         metatype_id.storeRelease(newId); \
1541         return newId; \
1542     } \
1543 }; \
1544 namespace QtPrivate { \
1545 template<typename T> \
1546 struct IsSequentialContainer<SINGLE_ARG_TEMPLATE<T> > \
1547 { \
1548     enum { Value = true }; \
1549 }; \
1550 } \
1551 QT_END_NAMESPACE
1552 
1553 #define Q_DECLARE_METATYPE_TEMPLATE_2ARG(DOUBLE_ARG_TEMPLATE) \
1554 QT_BEGIN_NAMESPACE \
1555 template<typename T, typename U> \
1556 struct QMetaTypeId< DOUBLE_ARG_TEMPLATE<T, U> > \
1557 { \
1558     enum { \
1559         Defined = QMetaTypeId2<T>::Defined && QMetaTypeId2<U>::Defined \
1560     }; \
1561     static int qt_metatype_id() \
1562     { \
1563         static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
1564         if (const int id = metatype_id.loadAcquire()) \
1565             return id; \
1566         const char *tName = QMetaType::fromType<T>().name(); \
1567         const char *uName = QMetaType::fromType<U>().name(); \
1568         Q_ASSERT(tName); \
1569         Q_ASSERT(uName); \
1570         const size_t tNameLen = qstrlen(tName); \
1571         const size_t uNameLen = qstrlen(uName); \
1572         QByteArray typeName; \
1573         typeName.reserve(sizeof(#DOUBLE_ARG_TEMPLATE) + 1 + tNameLen + 1 + uNameLen + 1 + 1); \
1574         typeName.append(#DOUBLE_ARG_TEMPLATE, int(sizeof(#DOUBLE_ARG_TEMPLATE)) - 1) \
1575             .append('<').append(tName, tNameLen).append(',').append(uName, uNameLen); \
1576         typeName.append('>'); \
1577         const int newId = qRegisterNormalizedMetaType< DOUBLE_ARG_TEMPLATE<T, U> >(typeName); \
1578         metatype_id.storeRelease(newId); \
1579         return newId; \
1580     } \
1581 }; \
1582 QT_END_NAMESPACE
1583 
1584 namespace QtPrivate {
1585 
1586 template<typename T, bool /* isSharedPointerToQObjectDerived */ = false>
1587 struct SharedPointerMetaTypeIdHelper
1588 {
1589     enum {
1590         Defined = 0
1591     };
1592     static int qt_metatype_id()
1593     {
1594         return -1;
1595     }
1596 };
1597 
1598 }
1599 
1600 #define Q_DECLARE_SMART_POINTER_METATYPE(SMART_POINTER) \
1601 QT_BEGIN_NAMESPACE \
1602 namespace QtPrivate { \
1603 template<typename T> \
1604 struct SharedPointerMetaTypeIdHelper<SMART_POINTER<T>, true> \
1605 { \
1606     enum { \
1607         Defined = 1 \
1608     }; \
1609     static int qt_metatype_id() \
1610     { \
1611         static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
1612         if (const int id = metatype_id.loadAcquire()) \
1613             return id; \
1614         const char * const cName = T::staticMetaObject.className(); \
1615         QByteArray typeName; \
1616         typeName.reserve(sizeof(#SMART_POINTER) + 1 + strlen(cName) + 1); \
1617         typeName.append(#SMART_POINTER, int(sizeof(#SMART_POINTER)) - 1) \
1618             .append('<').append(cName).append('>'); \
1619         const int newId = qRegisterNormalizedMetaType< SMART_POINTER<T> >(typeName); \
1620         metatype_id.storeRelease(newId); \
1621         return newId; \
1622     } \
1623 }; \
1624 template<typename T> \
1625 struct MetaTypeSmartPointerHelper<SMART_POINTER<T> , \
1626         typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type> \
1627 { \
1628     static bool registerConverter() \
1629     { \
1630         const QMetaType to = QMetaType(QMetaType::QObjectStar); \
1631         if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<SMART_POINTER<T>>(), to)) { \
1632             QtPrivate::QSmartPointerConvertFunctor<SMART_POINTER<T> > o; \
1633             return QMetaType::registerConverter<SMART_POINTER<T>, QObject*>(o); \
1634         } \
1635         return true; \
1636     } \
1637 }; \
1638 } \
1639 template <typename T> \
1640 struct QMetaTypeId< SMART_POINTER<T> > \
1641     : QtPrivate::SharedPointerMetaTypeIdHelper< SMART_POINTER<T>, \
1642                                                 QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value> \
1643 { \
1644 };\
1645 QT_END_NAMESPACE
1646 
1647 #define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER(TEMPLATENAME) \
1648     Q_DECLARE_METATYPE_TEMPLATE_1ARG(TEMPLATENAME)
1649 
1650 
1651 
1652 QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER)
1653 #undef Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE_ITER
1654 
1655 #define Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE Q_DECLARE_METATYPE_TEMPLATE_1ARG
1656 
1657 Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::vector)
1658 Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::list)
1659 
1660 #define Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(TEMPLATENAME) \
1661     QT_BEGIN_NAMESPACE \
1662     namespace QtPrivate { \
1663     template<typename T, typename U> \
1664     struct IsAssociativeContainer<TEMPLATENAME<T, U> > \
1665     { \
1666         enum { Value = true }; \
1667     }; \
1668     } \
1669     QT_END_NAMESPACE \
1670     Q_DECLARE_METATYPE_TEMPLATE_2ARG(TEMPLATENAME)
1671 
1672 
1673 Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(QHash)
1674 Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(QMap)
1675 Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(std::map)
1676 Q_DECLARE_METATYPE_TEMPLATE_2ARG(std::pair)
1677 
1678 #define Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER(TEMPLATENAME) \
1679     Q_DECLARE_SMART_POINTER_METATYPE(TEMPLATENAME)
1680 
1681 
1682 QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER)
1683 
1684 #undef Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER
1685 
1686 
1687 QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE)
1688 
1689 
1690 
1691 template <typename T>
1692 inline bool QtPrivate::IsMetaTypePair<T, true>::registerConverter()
1693 {
1694     const QMetaType to = QMetaType::fromType<QtMetaTypePrivate::QPairVariantInterfaceImpl>();
1695     if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) {
1696         QtMetaTypePrivate::QPairVariantInterfaceConvertFunctor<T> o;
1697         return QMetaType::registerConverter<T, QtMetaTypePrivate::QPairVariantInterfaceImpl>(o);
1698     }
1699     return true;
1700 } +/
1701 
1702 extern(C++, "QtPrivate") {
1703 
1704 /+ template<typename From>
1705 struct QSequentialIterableConvertFunctor
1706 {
1707     QIterable<QMetaSequence> operator()(const From &f) const
1708     {
1709         return QIterable<QMetaSequence>(QMetaSequence::fromContainer<From>(), &f);
1710     }
1711 }; +/
1712 
1713 struct QSequentialIterableMutableViewFunctor(From)
1714 {
1715     /+ValueClass!(QIterable!(QMetaSequence)) operator ()(ref From f) const
1716     {
1717         return QIterable!(QMetaSequence)(QMetaSequence.fromContainer!(From)(), &f);
1718     }+/
1719 }
1720 
1721 /+ template<typename T>
1722 struct SequentialValueTypeIsMetaType<T, true>
1723 {
1724     static bool registerConverter()
1725     {
1726         const QMetaType to = QMetaType::fromType<QIterable<QMetaSequence>>();
1727         if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) {
1728             QSequentialIterableConvertFunctor<T> o;
1729             return QMetaType::registerConverter<T, QIterable<QMetaSequence>>(o);
1730         }
1731         return true;
1732     }
1733 
1734     static bool registerMutableView()
1735     {
1736         const QMetaType to = QMetaType::fromType<QIterable<QMetaSequence>>();
1737         if (!QMetaType::hasRegisteredMutableViewFunction(QMetaType::fromType<T>(), to)) {
1738             QSequentialIterableMutableViewFunctor<T> o;
1739             return QMetaType::registerMutableView<T, QIterable<QMetaSequence>>(o);
1740         }
1741         return true;
1742     }
1743 };
1744 
1745 template<typename From>
1746 struct QAssociativeIterableConvertFunctor
1747 {
1748     QIterable<QMetaAssociation> operator()(const From &f) const
1749     {
1750         return QIterable<QMetaAssociation>(QMetaAssociation::fromContainer<From>(), &f);
1751     }
1752 }; +/
1753 
1754 struct QAssociativeIterableMutableViewFunctor(From)
1755 {
1756     /+ValueClass!(QIterable!(QMetaAssociation)) operator ()(ref From f) const
1757     {
1758         return QIterable!(QMetaAssociation)(QMetaAssociation.fromContainer!(From)(), &f);
1759     }+/
1760 }
1761 
1762 // Mapped type can be omitted, for example in case of a set.
1763 // However, if it is available, we want to instantiate the metatype here.
1764 /+ template<typename T>
1765 struct AssociativeKeyTypeIsMetaType<T, true> : AssociativeMappedTypeIsMetaType<T>
1766 {
1767     static bool registerConverter()
1768     {
1769         const QMetaType to = QMetaType::fromType<QIterable<QMetaAssociation>>();
1770         if (!QMetaType::hasRegisteredConverterFunction(QMetaType::fromType<T>(), to)) {
1771             QAssociativeIterableConvertFunctor<T> o;
1772             return QMetaType::registerConverter<T, QIterable<QMetaAssociation>>(o);
1773         }
1774         return true;
1775     }
1776 
1777     static bool registerMutableView()
1778     {
1779         const QMetaType to = QMetaType::fromType<QIterable<QMetaAssociation>>();
1780         if (!QMetaType::hasRegisteredMutableViewFunction(QMetaType::fromType<T>(), to)) {
1781             QAssociativeIterableMutableViewFunctor<T> o;
1782             return QMetaType::registerMutableView<T, QIterable<QMetaAssociation>>(o);
1783         }
1784         return true;
1785     }
1786 }; +/
1787 
1788 struct QTypeNormalizer
1789 {
1790     char* output;
1791     int len = 0;
1792     char last = 0;
1793 
1794 private:
1795     static bool is_ident_char(char s)
1796     {
1797         return ((s >= 'a' && s <= 'z') || (s >= 'A' && s <= 'Z') || (s >= '0' && s <= '9')
1798                 || s == '_');
1799     }
1800     static bool is_space(char s) { return (s == ' ' || s == '\t' || s == '\n'); }
1801     static bool is_number(char s) { return s >= '0' && s <= '9'; }
1802     static bool starts_with_token(const(char)* b, const(char)* e, const(char)* token,
1803                                                 bool msvcKw = false)
1804     {
1805         while (b != e && *token && *b == *token) {
1806             b++;
1807             token++;
1808         }
1809         if (*token)
1810             return false;
1811 /+ #ifdef Q_CC_MSVC
1812         /// On MSVC, keywords like class or struct are not separated with spaces in constexpr
1813         /// context
1814         if (msvcKw)
1815             return true;
1816 #endif
1817         Q_UNUSED(msvcKw) +/
1818         return b == e || !is_ident_char(*b);
1819     }
1820     static bool skipToken(ref const(char)* x, const(char)* e, const(char)* token,
1821                                         bool msvcKw = false)
1822     {
1823         if (!starts_with_token(x, e, token, msvcKw))
1824             return false;
1825         while (*token++)
1826             x++;
1827         while (x != e && is_space(*x))
1828             x++;
1829         return true;
1830     }
1831     static const(char)* skipString(const(char)* x, const(char)* e)
1832     {
1833         char delim = *x;
1834         x++;
1835         while (x != e && *x != delim) {
1836             if (*x == '\\') {
1837                 x++;
1838                 if (x == e)
1839                     return e;
1840             }
1841             x++;
1842         }
1843         if (x != e)
1844             x++;
1845         return x;
1846     }/+ ; +/
1847     static const(char)* skipTemplate(const(char)* x, const(char)* e, bool stopAtComa = false)
1848     {
1849         int scopeDepth = 0;
1850         int templateDepth = 0;
1851         while (x != e) {
1852             switch (*x) {
1853             case '<':
1854                 if (!scopeDepth)
1855                     templateDepth++;
1856                 break;
1857             case ',':
1858                 if (stopAtComa && !scopeDepth && !templateDepth)
1859                     return x;
1860                 break;
1861             case '>':
1862                 if (!scopeDepth)
1863                     if (--templateDepth < 0)
1864                         return x;
1865                 break;
1866             case '(':
1867             case '[':
1868             case '{':
1869                 scopeDepth++;
1870                 break;
1871             case '}':
1872             case ']':
1873             case ')':
1874                 scopeDepth--;
1875                 break;
1876             case '\'':
1877                 if (is_number(x[-1]))
1878                     break;
1879             goto case;
1880             case '\"':
1881                 x = skipString(x, e);
1882                 continue;default:
1883 
1884             }
1885             x++;
1886         }
1887         return x;
1888     }/+ ; +/
1889 
1890     void append(char x)
1891     {
1892         last = x;
1893         len++;
1894         if (output)
1895             *output++ = x;
1896     }
1897 
1898     void replaceLast(char x)
1899     {
1900         last = x;
1901         if (output)
1902             *(output - 1) = x;
1903     }
1904 
1905     void appendStr(const(char)* x)
1906     {
1907         while (*x)
1908             append(*x++);
1909     }/+ ; +/
1910 
1911     void normalizeIntegerTypes(ref const(char)* begin, const(char)* end)
1912     {
1913         int numLong = 0;
1914         int numSigned = 0;
1915         int numUnsigned = 0;
1916         int numInt = 0;
1917         int numShort = 0;
1918         int numChar = 0;
1919         while (begin < end) {
1920             if (skipToken(begin, end, "long")) {
1921                 numLong++;
1922                 continue;
1923             }
1924             if (skipToken(begin, end, "int")) {
1925                 numInt++;
1926                 continue;
1927             }
1928             if (skipToken(begin, end, "short")) {
1929                 numShort++;
1930                 continue;
1931             }
1932             if (skipToken(begin, end, "unsigned")) {
1933                 numUnsigned++;
1934                 continue;
1935             }
1936             if (skipToken(begin, end, "signed")) {
1937                 numSigned++;
1938                 continue;
1939             }
1940             if (skipToken(begin, end, "char")) {
1941                 numChar++;
1942                 continue;
1943             }
1944 /+ #ifdef Q_CC_MSVC
1945             if (skipToken(begin, end, "__int64")) {
1946                 numLong = 2;
1947                 continue;
1948             }
1949 #endif +/
1950             break;
1951         }
1952         if (numLong == 2)
1953             append('q'); // q(u)longlong
1954         if (numSigned && numChar)
1955             appendStr("signed ");
1956         else if (numUnsigned)
1957             appendStr("u");
1958         if (numChar)
1959             appendStr("char");
1960         else if (numShort)
1961             appendStr("short");
1962         else if (numLong == 1)
1963             appendStr("long");
1964         else if (numLong == 2)
1965             appendStr("longlong");
1966         else if (numUnsigned || numSigned || numInt)
1967             appendStr("int");
1968     }
1969 
1970     void skipStructClassOrEnum(ref const(char)* begin, const(char)* end)
1971     {
1972         // discard 'struct', 'class', and 'enum'; they are optional
1973         // and we don't want them in the normalized signature
1974         skipToken(begin, end, "struct", true) || skipToken(begin, end, "class", true)
1975                 || skipToken(begin, end, "enum", true);
1976     }
1977 
1978     void skipQtNamespace(ref const(char)* begin, const(char)* end)
1979     {
1980 /+ #ifdef QT_NAMESPACE
1981         const char *nsbeg = begin;
1982         if (skipToken(nsbeg, end, QT_STRINGIFY(QT_NAMESPACE)) && nsbeg + 2 < end && nsbeg[0] == ':'
1983             && nsbeg[1] == ':') {
1984             begin = nsbeg + 2;
1985             while (begin != end && is_space(*begin))
1986                 begin++;
1987         }
1988 #else
1989         Q_UNUSED(begin) +/
1990         /+ Q_UNUSED(end) +/
1991 /+ #endif +/
1992     }
1993 
1994 public:
1995 /+ #if defined(Q_CC_CLANG) || defined (Q_CC_GNU) +/
1996     // this is much simpler than the full type normalization below
1997     // the reason is that the signature returned by Q_FUNC_INFO is already
1998     // normalized to the largest degree, and we need to do only small adjustments
1999     /+int normalizeTypeFromSignature(const(char)* begin, const(char)* end)
2000     {
2001         // bail out if there is an anonymous struct
2002         auto name = /+ std:: +/string_view(begin, end-begin);
2003 /+ #if defined (Q_CC_CLANG)
2004         if (name.find("anonymous ") != std::string_view::npos)
2005             return normalizeType(begin, end);
2006 #else +/
2007         if (name.find("unnamed ".ptr) != /+ std:: +/string_view.npos)
2008             return normalizeType(begin, end);
2009 /+ #endif +/
2010         while (begin < end) {
2011             if (*begin == ' ') {
2012                 if (last == ',' || last == '>' || last == '<' || last == '*' || last == '&') {
2013                     ++begin;
2014                     continue;
2015                 }
2016             }
2017             if (last == ' ') {
2018                 if (*begin == '*' || *begin == '&' || *begin == '(') {
2019                     replaceLast(*begin);
2020                     ++begin;
2021                     continue;
2022                 }
2023             }
2024             if (!is_ident_char(last)) {
2025                 skipStructClassOrEnum(begin, end);
2026                 if (begin == end)
2027                     break;
2028 
2029                 skipQtNamespace(begin, end);
2030                 if (begin == end)
2031                     break;
2032 
2033                 normalizeIntegerTypes(begin, end);
2034                 if (begin == end)
2035                     break;
2036             }
2037             append(*begin);
2038             ++begin;
2039         }
2040         return len;
2041     }+/
2042 /+ #else
2043     // MSVC needs the full normalization, as it puts the const in a different
2044     // place than we expect
2045     constexpr int normalizeTypeFromSignature(const char *begin, const char *end)
2046     { return normalizeType(begin, end); }
2047 #endif +/
2048 
2049     int normalizeType(const(char)* begin, const(char)* end, bool adjustConst = true)
2050     {
2051         // Trim spaces
2052         while (begin != end && is_space(*begin))
2053             begin++;
2054         while (begin != end && is_space(*(end - 1)))
2055             end--;
2056 
2057         // Convert 'char const *' into 'const char *'. Start at index 1,
2058         // not 0, because 'const char *' is already OK.
2059         const(char)* cst = begin + 1;
2060         if (*begin == '\'' || *begin == '"')
2061             cst = skipString(begin, end);
2062         bool seenStar = false;
2063         bool hasMiddleConst = false;
2064         while (cst < end) {
2065             if (*cst == '\"' || (*cst == '\'' && !is_number(cst[-1]))) {
2066                 cst = skipString(cst, end);
2067                 if (cst == end)
2068                     break;
2069             }
2070 
2071             // We mustn't convert 'char * const *' into 'const char **'
2072             // and we must beware of 'Bar<const Bla>'.
2073             if (*cst == '&' || *cst == '*' || *cst == '[') {
2074                 seenStar = *cst != '&' || cst != (end - 1);
2075                 break;
2076             }
2077             if (*cst == '<') {
2078                 cst = skipTemplate(cst + 1, end);
2079                 if (cst == end)
2080                     break;
2081             }
2082             cst++;
2083             const(char)* skipedCst = cst;
2084             if (!is_ident_char(*(cst - 1)) && skipToken(skipedCst, end, "const")) {
2085                 const(char)* testEnd = end;
2086                 while (skipedCst < testEnd--) {
2087                     if (*testEnd == '*' || *testEnd == '['
2088                         || (*testEnd == '&' && testEnd != (end - 1))) {
2089                         seenStar = true;
2090                         break;
2091                     }
2092                     if (*testEnd == '>')
2093                         break;
2094                 }
2095                 if (adjustConst && !seenStar) {
2096                     if (*(end - 1) == '&')
2097                         end--;
2098                 } else {
2099                     appendStr("const ");
2100                 }
2101                 normalizeType(begin, cst, false);
2102                 begin = skipedCst;
2103                 hasMiddleConst = true;
2104                 break;
2105             }
2106         }
2107         if (skipToken(begin, end, "const")) {
2108             if (adjustConst && !seenStar) {
2109                 if (*(end - 1) == '&')
2110                     end--;
2111             } else {
2112                 appendStr("const ");
2113             }
2114         }
2115         if (seenStar && adjustConst) {
2116             const(char)* e = end;
2117             if (*(end - 1) == '&' && *(end - 2) != '&')
2118                 e--;
2119             while (begin != e && is_space(*(e - 1)))
2120                 e--;
2121             const(char)* token = "tsnoc"; // 'const' reverse, to check if it ends with const
2122             while (*token && begin != e && *(--e) == *token++)
2123                 {}
2124             if (!*token && begin != e && !is_ident_char(*(e - 1))) {
2125                 while (begin != e && is_space(*(e - 1)))
2126                     e--;
2127                 end = e;
2128             }
2129         }
2130 
2131         skipStructClassOrEnum(begin, end);
2132         skipQtNamespace(begin, end);
2133 
2134         if (skipToken(begin, end, "QVector")) {
2135             // Replace QVector by QList
2136             appendStr("QList");
2137         }
2138 
2139         if (skipToken(begin, end, "QPair")) {
2140             // replace QPair by std::pair
2141             appendStr("std::pair");
2142         }
2143 
2144         if (!hasMiddleConst)
2145             // Normalize the integer types
2146             normalizeIntegerTypes(begin, end);
2147 
2148         bool spaceSkiped = true;
2149         while (begin != end) {
2150             char c = *begin++;
2151             if (is_space(c)) {
2152                 spaceSkiped = true;
2153             } else if ((c == '\'' && !is_number(last)) || c == '\"') {
2154                 begin--;
2155                 auto x = skipString(begin, end);
2156                 while (begin < x)
2157                     append(*begin++);
2158             } else {
2159                 if (spaceSkiped && is_ident_char(last) && is_ident_char(c))
2160                     append(' ');
2161                 append(c);
2162                 spaceSkiped = false;
2163                 if (c == '<') {
2164                     do {
2165                         // template recursion
2166                         const(char)* tpl = skipTemplate(begin, end, true);
2167                         normalizeType(begin, tpl, false);
2168                         if (tpl == end)
2169                             return len;
2170                         append(*tpl);
2171                         begin = tpl;
2172                     } while (*begin++ == ',');
2173                 }
2174             }
2175         }
2176         return len;
2177     }
2178 }
2179 
2180 // Normalize the type between begin and end, and store the data in the output. Returns the length.
2181 // The idea is to first run this function with nullptr as output to allocate the output with the
2182 // size
2183 /+int qNormalizeType(const(char)* begin, const(char)* end, char* output)
2184 {
2185     return QTypeNormalizer { output} .normalizeType(begin, end);
2186 }+/
2187 
2188 /+ template<typename T>
2189 struct is_std_pair : std::false_type {};
2190 
2191 template <typename T1_, typename T2_>
2192 struct is_std_pair<std::pair<T1_, T2_>> : std::true_type {
2193     using T1 = T1_;
2194     using T2 = T2_;
2195 }; +/
2196 
2197 extern(D) auto typenameHelper(T)()
2198 {
2199     /+ if constexpr (is_std_pair<T>::value) {
2200         using T1 = typename is_std_pair<T>::T1;
2201         using T2 = typename is_std_pair<T>::T2;
2202         std::remove_const_t<std::conditional_t<bool (QMetaTypeId2<T1>::IsBuiltIn), typename QMetaTypeId2<T1>::NameAsArrayType, decltype(typenameHelper<T1>())>> t1Name {};
2203         std::remove_const_t<std::conditional_t<bool (QMetaTypeId2<T2>::IsBuiltIn), typename QMetaTypeId2<T2>::NameAsArrayType, decltype(typenameHelper<T2>())>> t2Name {};
2204         if constexpr (bool (QMetaTypeId2<T1>::IsBuiltIn) ) {
2205             t1Name = QMetaTypeId2<T1>::nameAsArray;
2206         } else {
2207             t1Name = typenameHelper<T1>();
2208         }
2209         if constexpr (bool(QMetaTypeId2<T2>::IsBuiltIn)) {
2210             t2Name = QMetaTypeId2<T2>::nameAsArray;
2211         } else {
2212             t2Name = typenameHelper<T2>();
2213         }
2214         constexpr auto nonTypeDependentLen = sizeof("std::pair<,>");
2215         constexpr auto t1Len = t1Name.size() - 1;
2216         constexpr auto t2Len = t2Name.size() - 1;
2217         constexpr auto length = nonTypeDependentLen + t1Len + t2Len;
2218         std::array<char, length + 1> result {};
2219         constexpr auto prefix = "std::pair<";
2220         int currentLength = 0;
2221         for (; currentLength < int(sizeof("std::pair<") - 1); ++currentLength)
2222             result[currentLength] = prefix[currentLength];
2223         for (int i = 0; i < int(t1Len); ++currentLength, ++i)
2224             result[currentLength] = t1Name[i];
2225         result[currentLength++] = ',';
2226         for (int i = 0; i < int(t2Len); ++currentLength, ++i)
2227             result[currentLength] = t2Name[i];
2228         result[currentLength++] = '>';
2229         result[currentLength++] = '\0';
2230         return result;
2231     } else +/ {
2232         immutable(char[T.stringof.length + 1]) result = T.stringof;
2233         //QTypeNormalizer{ result.data()} .normalizeTypeFromSignature(begin, end);
2234         // TODO: Use the same name as Qt.
2235         return result;
2236     }
2237 }
2238 
2239 struct BuiltinMetaType(T)
2240 {
2241     static if(QMetaTypeId2!(T).IsBuiltIn)
2242         enum int value = QMetaTypeId2!(T).MetaType;
2243     else
2244         enum int value = 0;
2245 }
2246 
2247 struct QEqualityOperatorForType(T, /+ bool +/ /+ = (QTypeTraits::has_operator_equal_v<T> && !std::is_pointer_v<T>) +/)
2248 {
2249 /+ QT_WARNING_PUSH
2250 QT_WARNING_DISABLE_FLOAT_COMPARE +/
2251     static bool equals(const(QMetaTypeInterface)* , const(void)* a, const(void)* b)
2252     { return *reinterpret_cast!(const(T)*)(a) == *reinterpret_cast!(const(T)*)(b); }
2253 /+ QT_WARNING_POP +/
2254 }
2255 
2256 /+ template<typename T>
2257 struct QEqualityOperatorForType <T, false>
2258 {
2259     static constexpr QMetaTypeInterface::EqualsFn equals = nullptr;
2260 }; +/
2261 
2262 struct QLessThanOperatorForType(T, /+ bool +/ /+ = (QTypeTraits::has_operator_less_than_v<T> && !std::is_pointer_v<T>) +/)
2263 {
2264     static bool lessThan(const(QMetaTypeInterface)* , const(void)* a, const(void)* b)
2265     { return *reinterpret_cast!(const(T)*)(a) < *reinterpret_cast!(const(T)*)(b); }
2266 }
2267 
2268 /+ template<typename T>
2269 struct QLessThanOperatorForType <T, false>
2270 {
2271     static constexpr QMetaTypeInterface::LessThanFn lessThan = nullptr;
2272 }; +/
2273 
2274 struct QDebugStreamOperatorForType(T, /+ bool +/ /+ = (QTypeTraits::has_ostream_operator_v<QDebug, T> && !std::is_pointer_v<T>) +/)
2275 {
2276     /+ static void debugStream(const QMetaTypeInterface *, QDebug &dbg, const void *a)
2277     { dbg << *reinterpret_cast<const T *>(a); } +/
2278 }
2279 
2280 /+ template<typename T>
2281 struct QDebugStreamOperatorForType <T, false>
2282 {
2283     static constexpr QMetaTypeInterface::DebugStreamFn debugStream = nullptr;
2284 }; +/
2285 
2286 
2287 struct QDataStreamOperatorForType(T, /+ bool +/ /+ = QTypeTraits::has_stream_operator_v<QDataStream, T>> +/)
2288 {
2289     static void dataStreamOut(const(QMetaTypeInterface)* , ref QDataStream ds, const(void)* a)
2290     { ds << *reinterpret_cast!(const(T)*)(a); }
2291     static void dataStreamIn(const(QMetaTypeInterface)* , ref QDataStream ds, void* a)
2292     { ds >> *reinterpret_cast!(T*)(a); }
2293 }
2294 
2295 /+ template<typename T>
2296 struct QDataStreamOperatorForType <T, false>
2297 {
2298     static constexpr QMetaTypeInterface::DataStreamOutFn dataStreamOut = nullptr;
2299     static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr;
2300 }; +/
2301 
2302 class QMetaTypeForType(S)
2303 {
2304 public:
2305     extern(D) static immutable name = typenameHelper!(S)();
2306 
2307     static QMetaTypeInterface.DefaultCtrFn getDefaultCtr()
2308     {
2309         import core.lifetime;
2310 
2311         static if (__traits(compiles, {S s;}) || __traits(hasMember, S, "rawConstructor")) {
2312             return (const QMetaTypeInterface *, void *addr) {
2313                 static if(__traits(hasMember, S, "rawConstructor")) {
2314                     (cast(S*)addr).rawConstructor();
2315                 } else {
2316                     emplace!S(cast(S*)addr);
2317                 }
2318             };
2319         } else {
2320             return null;
2321         }
2322     }
2323 
2324     static QMetaTypeInterface.CopyCtrFn getCopyCtr()
2325     {
2326         import core.lifetime;
2327 
2328         static if (__traits(compiles, (ref S other){S s = other;})) {
2329             return (const QMetaTypeInterface *, void *addr, const void *other) {
2330                 static if(is(S == struct) && __traits(hasCopyConstructor, S)) {
2331                     // Workaround for https://issues.dlang.org/show_bug.cgi?id=22766
2332                     import core.stdc.string;
2333                     memset(addr, 0, S.sizeof);
2334                     (*cast(S*)addr).__ctor(*cast(S*)other);
2335                 } else {
2336                     copyEmplace!S(*cast(S*)other, *cast(S*)addr);
2337                 }
2338             };
2339         } else {
2340             return null;
2341         }
2342     }
2343 
2344     static QMetaTypeInterface.MoveCtrFn getMoveCtr()
2345     {
2346         import core.lifetime;
2347 
2348         static if (0 /*/+ std:: +/is_move_constructible_v!(S)*/) {
2349             return (const QMetaTypeInterface *, void *addr, void *other) {
2350                 emplace!S(cast(S*)addr, /+ std:: +/move(*reinterpret_cast!(S*)(other)));
2351             };
2352         } else {
2353             return null;
2354         }
2355     }
2356 
2357     static QMetaTypeInterface.DtorFn getDtor()
2358     {
2359         static if (1 /*/+ std:: +/is_destructible_v!(S) && !/+ std:: +/is_trivially_destructible_v!(S)*/)
2360             return (const QMetaTypeInterface *, void *addr) {
2361                 destroy!false(*reinterpret_cast!(S*)(addr));
2362             };
2363         else
2364             return null;
2365     }
2366 
2367     static QMetaTypeInterface.LegacyRegisterOp getLegacyRegister()
2368     {
2369         static if (QMetaTypeId2!(S).Defined && !QMetaTypeId2!(S).IsBuiltIn) {
2370             return () { QMetaTypeId2!(S).qt_metatype_id(); };
2371         } else {
2372             return null;
2373         }
2374     }
2375 
2376     static const(char)* getName()
2377     {
2378         static if (cast(bool)(QMetaTypeId2!(S).IsBuiltIn)) {
2379             return QMetaTypeId2!(S).nameAsArray.ptr;
2380         } else {
2381             return name.ptr;
2382         }
2383     }
2384 }
2385 
2386 
2387 struct QMetaTypeInterfaceWrapper(T)
2388 {
2389     extern(D) static immutable QMetaTypeInterface metaType = {
2390         /*.revision=*/ 0,
2391         /*.alignment=*/ T.alignof,
2392         /*.size=*/ T.sizeof,
2393         /*.flags=*/ QMetaTypeTypeFlags!(T).Flags,
2394         /*.typeId=*/ QBasicAtomicInt(BuiltinMetaType!(T).value),
2395         /*.metaObjectFn=*/ MetaObjectForType!(T).metaObjectFunction,
2396         /*.name=*/ QMetaTypeForType!(T).getName(),
2397         /*.defaultCtr=*/ QMetaTypeForType!(T).getDefaultCtr(),
2398         /*.copyCtr=*/ QMetaTypeForType!(T).getCopyCtr(),
2399         /*.moveCtr=*/ QMetaTypeForType!(T).getMoveCtr(),
2400         /*.dtor=*/ QMetaTypeForType!(T).getDtor(),
2401 //        /*.equals=*/ &QEqualityOperatorForType!(T).equals,
2402 //        /*.lessThan=*/ &QLessThanOperatorForType!(T).lessThan,
2403 //        /*.debugStream=*/ QDebugStreamOperatorForType!(T).debugStream,
2404 //        /*.dataStreamOut=*/ &QDataStreamOperatorForType!(T).dataStreamOut,
2405 //        /*.dataStreamIn=*/ &QDataStreamOperatorForType!(T).dataStreamIn,
2406 //        /*.legacyRegisterOp=*/ QMetaTypeForType!(T).getLegacyRegister()
2407     };
2408 };
2409 
2410 
2411 struct QMetaTypeInterfaceWrapper(T: void)
2412 {
2413     static immutable QMetaTypeInterface metaType =
2414     {
2415         /*.revision=*/ 0,
2416         /*.alignment=*/ 0,
2417         /*.size=*/ 0,
2418         /*.flags=*/ 0,
2419         /*.typeId=*/ BuiltinMetaType!(void).value,
2420         /*.metaObjectFn=*/ null,
2421         /*.name=*/ "void",
2422         /*.defaultCtr=*/ null,
2423         /*.copyCtr=*/ null,
2424         /*.moveCtr=*/ null,
2425         /*.dtor=*/ null,
2426         /*.equals=*/ null,
2427         /*.lessThan=*/ null,
2428         /*.debugStream=*/ null,
2429         /*.dataStreamOut=*/ null,
2430         /*.dataStreamIn=*/ null,
2431         /*.legacyRegisterOp=*/ null
2432     };
2433 };
2434 /+ #undef QT_METATYPE_CONSTEXPRLAMDA
2435 
2436 #ifndef QT_BOOTSTRAPPED
2437 
2438 #if !defined(Q_CC_MSVC) || !defined(QT_BUILD_CORE_LIB)
2439 #define QT_METATYPE_TEMPLATE_EXPORT Q_CORE_EXPORT
2440 #else
2441 #define QT_METATYPE_TEMPLATE_EXPORT
2442 #endif
2443 
2444 #define QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER(TypeName, Id, Name)                               \
2445     extern template class QT_METATYPE_TEMPLATE_EXPORT QMetaTypeForType<Name>;
2446 QT_WARNING_PUSH
2447 QT_WARNING_DISABLE_GCC("-Wattributes") // false positive because of QMetaTypeForType<void>
2448 QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2449 QT_WARNING_POP
2450 QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2451 QT_FOR_EACH_STATIC_CORE_CLASS(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2452 QT_FOR_EACH_STATIC_CORE_POINTER(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2453 QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER)
2454 #undef QT_METATYPE_DECLARE_EXTERN_TEMPLATE_ITER
2455 #undef QT_METATYPE_TEMPLATE_EXPORT
2456 #endif +/
2457 
2458 const(QMetaTypeInterface)* qMetaTypeInterfaceForType(T)()
2459 {
2460     import std.traits;
2461     alias Ty = Unqual!(T);
2462     return &QMetaTypeInterfaceWrapper!(Ty).metaType;
2463 }
2464 
2465 extern(C++, "detail") {
2466 /+struct is_complete_helper(T, ODR_VIOLATION_PREVENTER)
2467 {
2468     /+ template<typename U> +/
2469     static auto check(U)()/+ (U *) -> std::integral_constant<bool, sizeof(U) != 0> +/;
2470     static auto check()/+ (...) -> std::false_type +/;
2471     alias type = /+ decltype(check(static_cast<T *>(nullptr))) +/false_type;
2472 }+/
2473 } // namespace detail
2474 
2475 struct is_complete(T, ODR_VIOLATION_PREVENTER) {
2476     /+ detail:: +/is_complete_helper!(T, ODR_VIOLATION_PREVENTER).is_complete_helper.type base0;
2477     alias base0 this;
2478 }
2479 
2480 struct qRemovePointerLike(T)
2481 {
2482     alias type = /+ std:: +/remove_pointer_t!(T);
2483 }
2484 
2485 /+ #define Q_REMOVE_POINTER_LIKE_IMPL(Pointer) \
2486 template <typename T> \
2487 struct qRemovePointerLike<Pointer<T>> \
2488 { \
2489     using type = T; \
2490 };
2491 
2492 QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(Q_REMOVE_POINTER_LIKE_IMPL) +/
2493 alias qRemovePointerLike_t(T) = qRemovePointerLike!(T).type;
2494 /+ #undef Q_REMOVE_POINTER_LIKE_IMPL +/
2495 
2496 struct TypeAndForceComplete(T, ForceComplete_)
2497 {
2498     alias type = T;
2499     alias ForceComplete = ForceComplete_;
2500 }
2501 
2502 /+ template<typename Unique, typename TypeCompletePair>
2503 constexpr const QMetaTypeInterface *qTryMetaTypeInterfaceForType()
2504 {
2505     using T = typename TypeCompletePair::type;
2506     using ForceComplete = typename TypeCompletePair::ForceComplete;
2507     using Ty = std::remove_cv_t<std::remove_reference_t<T>>;
2508     using Tz = qRemovePointerLike_t<Ty>;
2509     if constexpr (!is_complete<Tz, Unique>::value && !ForceComplete::value) {
2510         return nullptr;
2511     } else {
2512         return &QMetaTypeInterfaceWrapper<Ty>::metaType;
2513     }
2514 } +/
2515 
2516 } // namespace QtPrivate
2517 
2518 /+ template<typename T>
2519 constexpr QMetaType QMetaType::fromType()
2520 {
2521     return QMetaType(QtPrivate::qMetaTypeInterfaceForType<T>());
2522 }
2523 
2524 template<typename... T>
2525 constexpr const QtPrivate::QMetaTypeInterface *const qt_metaTypeArray[] = {
2526     QtPrivate::qMetaTypeInterfaceForType<T>()...
2527 };
2528 
2529 template<typename Unique,typename... T>
2530 constexpr const QtPrivate::QMetaTypeInterface *const qt_incomplete_metaTypeArray[] = {
2531     QtPrivate::qTryMetaTypeInterfaceForType<Unique, T>()...
2532 }; +/
2533 
2534 template qt_incomplete_metaTypeArray(Unique, T...)
2535 {
2536     mixin((){
2537         import std.conv;
2538         string code = text("extern(D) const __gshared QMetaTypeInterface*[", T.length, "] qt_incomplete_metaTypeArray = [");
2539         code ~= "T";
2540         code ~= "];";
2541         return code;
2542     }());
2543 }
2544 
2545 /+ Q_DECLARE_METATYPE(QtMetaTypePrivate::QPairVariantInterfaceImpl) +/
2546