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