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.nativeinterface;
13 extern(C++):
14 
15 import qt.config;
16 import qt.helpers;
17 
18 // We declare a virtual non-inline function in the form
19 // of the destructor, making it the key function. This
20 // ensures that the typeinfo of the class is exported.
21 // By being protected, we also ensure that pointers to
22 // the interface can't be deleted.
23 /+ #define QT_DECLARE_NATIVE_INTERFACE_3(NativeInterface, Revision, BaseType) \
24     protected: \
25         virtual ~NativeInterface(); \
26         \
27         struct TypeInfo { \
28             using baseType = BaseType; \
29             static constexpr char const *name = QT_STRINGIFY(NativeInterface); \
30             static constexpr int revision = Revision; \
31         }; \
32         \
33         template <typename, typename> \
34         friend struct QNativeInterface::Private::has_type_info; \
35         \
36         template <typename> \
37         friend bool constexpr QNativeInterface::Private::hasTypeInfo(); \
38         \
39         template <typename> \
40         friend struct QNativeInterface::Private::TypeInfo; \
41     public: \
42         NativeInterface() = default; \
43         Q_DISABLE_COPY_MOVE(NativeInterface)
44 
45 // Revisioned interfaces only make sense when exposed through a base
46 // type via QT_DECLARE_NATIVE_INTERFACE_ACCESSOR, as the revision
47 // checks happen at that level (and not for normal dynamic_casts).
48 #define QT_DECLARE_NATIVE_INTERFACE_2(NativeInterface, Revision) \
49     static_assert(false, "Must provide a base type when specifying revision");
50 
51 #define QT_DECLARE_NATIVE_INTERFACE_1(NativeInterface) \
52     QT_DECLARE_NATIVE_INTERFACE_3(NativeInterface, 0, void)
53 
54 #define QT_DECLARE_NATIVE_INTERFACE(...) \
55     QT_OVERLOADED_MACRO(QT_DECLARE_NATIVE_INTERFACE, __VA_ARGS__)
56 
57 namespace QNativeInterface::Private { +/
58 
59     // Basic type-trait to verify that a given native interface has
60     // all the required type information for us to evaluate it.
61     struct has_type_info(NativeInterface, ) {
62         /+ std:: +/false_type base0;
63         alias base0 this;
64 }
65 
66     // The type-trait is friended by TypeInfo, so that we can
67     // evaluate TypeInfo in the template arguments.
68     /+ template <typename NativeInterface>
69     struct has_type_info<NativeInterface, std::void_t<
70         typename NativeInterface::TypeInfo,
71         typename NativeInterface::TypeInfo::baseType,
72         decltype(&NativeInterface::TypeInfo::name),
73         decltype(&NativeInterface::TypeInfo::revision)
74         >> : std::true_type {}; +/
75 
76     // We need to wrap the instantiation of has_type_info in a
77     // function friended by TypeInfo, otherwise MSVC will not
78     // let us evaluate TypeInfo in the template arguments.
79     bool hasTypeInfo(NativeInterface)()
80     {
81         return has_type_info!(NativeInterface__1).value;
82     }
83 
84     struct TypeInfo(NativeInterface)
85     {
86         // To ensure SFINAE works for hasTypeInfo we can't use it in a constexpr
87         // variable that also includes an expression that relies on the type
88         // info. This helper variable is okey, as it it self contained.
89         extern(D) static immutable bool haveTypeInfo = hasTypeInfo!(NativeInterface__1)();
90 
91         // We can then use the helper variable in a constexpr condition in a
92         // function, which does not break SFINAE if haveTypeInfo is false.
93         /+ template <typename BaseType> +/
94         /+ static constexpr bool isCompatibleHelper()
95         {
96             if constexpr (haveTypeInfo)
97                 return std::is_base_of<typename NativeInterface::TypeInfo::baseType, BaseType>::value;
98             else
99                 return false;
100         } +/
101 
102         // MSVC however doesn't like constexpr functions in enable_if_t conditions,
103         // so we need to wrap it yet again in a constexpr variable. This is fine,
104         // as all the SFINAE magic has been resolved at this point.
105         /+ template <typename BaseType> +/
106         /+ static constexpr bool isCompatibleWith = isCompatibleHelper<BaseType>(); +/
107 
108         // The revision and name accessors are not used in enable_if_t conditions,
109         // so we can leave them as constexpr functions. As this class template is
110         // friended by TypeInfo we can access the protected members of TypeInfo.
111         static int revision()
112         {
113             static if (haveTypeInfo)
114                 return cast(int)(NativeInterface__1.TypeInfo.revision);
115             else
116                 return 0;
117         }
118 
119         static const(char)* name()
120         {
121             static if (haveTypeInfo)
122                 return cast(const(char)*)(&NativeInterface__1.TypeInfo.name);
123             else
124                 return null;
125         }
126     }
127 
128     // Wrapper type to make the error message in case
129     // of incompatible interface types read better.
130     struct NativeInterface(I) {
131         TypeInfo!(I) base0;
132         alias base0 this;
133 }
134 /+ } // QNativeInterface::Private
135 
136 // Declares an accessor for the native interface
137 #ifdef Q_QDOC
138 #define QT_DECLARE_NATIVE_INTERFACE_ACCESSOR(T) \
139     template <typename QNativeInterface> \
140     QNativeInterface *nativeInterface() const;
141 #else +/
142 /+ #define QT_DECLARE_NATIVE_INTERFACE_ACCESSOR(T) \
143     template <typename NativeInterface, typename TypeInfo = QNativeInterface::Private::NativeInterface<NativeInterface>, \
144     typename BaseType = T, std::enable_if_t<TypeInfo::template isCompatibleWith<T>, bool> = true> \
145     NativeInterface *nativeInterface() const \
146     { \
147         return static_cast<NativeInterface*>(resolveInterface( \
148             TypeInfo::name(), TypeInfo::revision())); \
149     } \
150     protected: \
151         void *resolveInterface(const char *name, int revision) const; \
152     public: +/
153 extern(D) alias QT_DECLARE_NATIVE_INTERFACE_ACCESSOR = function string(string T)
154 {
155     return
156             mixin(interpolateMixin(q{/+ template <typename NativeInterface, typename TypeInfo = QNativeInterface::Private::NativeInterface<NativeInterface>,
157             typename BaseType = T, std::enable_if_t<TypeInfo::template isCompatibleWith<T>, bool> = true> +/
158             /+ NativeInterface *nativeInterface() const
159             {
160                 return static_cast<NativeInterface*>(resolveInterface(
161                     TypeInfo::name(), TypeInfo::revision()));
162             } +/
163             protected:
164                 /+ void *resolveInterface(const char *name, int revision) const; +/
165             public:}));
166 };
167 /+ #endif +/
168