File indexing completed on 2024-06-23 05:08:44
0001 /* 0002 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef KANDROIDEXTRAS_JNIPROPERTIES_H 0008 #define KANDROIDEXTRAS_JNIPROPERTIES_H 0009 0010 #include "jniargument.h" 0011 #include "jniobject.h" 0012 #include "jnisignature.h" 0013 #include "jnitypes.h" 0014 #include "jnitypetraits.h" 0015 0016 #include <type_traits> 0017 0018 namespace KAndroidExtras { 0019 0020 namespace Jni { 0021 template <typename T> class Array; 0022 } 0023 0024 /** @cond internal */ 0025 namespace Internal { 0026 0027 /** Wrapper for static properties. */ 0028 template <typename PropType, typename ClassType, typename NameHolder, bool PrimitiveType> struct StaticProperty {}; 0029 template <typename PropType, typename ClassType, typename NameHolder> 0030 struct StaticProperty<PropType, ClassType, NameHolder, false> { 0031 static_assert(!is_invalid_primitive_type<PropType>::value, "Using an incompatible primitive type!"); 0032 inline QJniObject get() const 0033 { 0034 return QJniObject::getStaticObjectField(Jni::typeName<ClassType>(), Jni::typeName<NameHolder>(), Jni::signature<PropType>()); 0035 } 0036 inline operator QJniObject() const 0037 { 0038 return get(); 0039 } 0040 inline operator typename Jni::converter<PropType>::type() const 0041 { 0042 return Jni::converter<PropType>::convert(get()); 0043 } 0044 template <typename RetT = PropType, typename = std::enable_if_t<Jni::is_generic_wrapper<PropType>::value, RetT>> 0045 inline operator Jni::Object<PropType>() const 0046 { 0047 return Jni::Object<PropType>(get()); 0048 } 0049 }; 0050 0051 template <typename PropType, typename ClassType, typename NameHolder> 0052 struct StaticProperty<PropType, ClassType, NameHolder, true> { 0053 inline operator auto() const 0054 { 0055 return primitive_value<PropType>::fromJni(QJniObject::getStaticField<typename primitive_value<PropType>::JniType>(Jni::typeName<ClassType>(), Jni::typeName<NameHolder>())); 0056 } 0057 }; 0058 0059 /** Shared code for non-static property wrappers. */ 0060 template <typename ClassType, typename OffsetHolder> 0061 class PropertyBase { 0062 protected: 0063 inline QJniObject handle() const { 0064 const auto owner = reinterpret_cast<const ClassType*>(reinterpret_cast<const char*>(this) - OffsetHolder::offset()); 0065 return owner->jniHandle(); 0066 } 0067 }; 0068 0069 /** Wrapper for non-static properties. */ 0070 template <typename PropType, typename ClassType, typename NameHolder, typename OffsetHolder, bool PrimitiveType> struct Property {}; 0071 template <typename PropType, typename ClassType, typename NameHolder, typename OffsetHolder> 0072 class Property<PropType, ClassType, NameHolder, OffsetHolder, false> : public PropertyBase<ClassType, OffsetHolder> { 0073 private: 0074 struct _jni_NoType {}; 0075 static_assert(!is_invalid_primitive_type<PropType>::value, "Using an incompatible primitive type!"); 0076 public: 0077 inline QJniObject get() const 0078 { 0079 return this->handle().getObjectField(Jni::typeName<NameHolder>(), Jni::signature<PropType>()); 0080 } 0081 inline operator QJniObject() const 0082 { 0083 return get(); 0084 } 0085 inline operator typename Jni::converter<PropType>::type() const 0086 { 0087 return Jni::converter<PropType>::convert(get()); 0088 } 0089 template <typename RetT = PropType, typename = std::enable_if_t<Jni::is_array<PropType>::value, RetT>> 0090 inline operator PropType() const 0091 { 0092 return PropType(get()); 0093 } 0094 template <typename RetT = PropType, typename = std::enable_if_t<Jni::is_generic_wrapper<PropType>::value, RetT>> 0095 inline operator Jni::Object<PropType>() const 0096 { 0097 return Jni::Object<PropType>(get()); 0098 } 0099 0100 inline Property& operator=(typename Internal::argument<PropType>::type value) 0101 { 0102 this->handle().setField(Jni::typeName<NameHolder>(), Jni::signature<PropType>(), Internal::argument<PropType>::toCallArgument(value)); 0103 return *this; 0104 } 0105 inline Property& operator=(const QJniObject &value) 0106 { 0107 this->handle().setField(Jni::typeName<NameHolder>(), Jni::signature<PropType>(), value.object()); 0108 return *this; 0109 } 0110 inline Property& operator=(const typename std::conditional<std::is_same_v<typename Jni::converter<PropType>::type, void>, _jni_NoType, typename Jni::converter<PropType>::type>::type &value) 0111 { 0112 this->handle().setField(Jni::typeName<NameHolder>(), Jni::signature<PropType>(), Jni::reverse_converter<PropType>::type::convert(value).object()); 0113 return *this; 0114 } 0115 0116 // special case for string comparison, which is often done against different types and thus the implicit conversion operator 0117 // isn't going to be enough 0118 template <typename CmpT, typename = std::enable_if_t<std::is_same_v<PropType, java::lang::String>, CmpT>> 0119 inline bool operator==(const CmpT &other) const 0120 { 0121 return QString(*this) == other; 0122 } 0123 }; 0124 0125 template <typename PropType, typename ClassType, typename NameHolder, typename OffsetHolder> 0126 class Property<PropType, ClassType, NameHolder, OffsetHolder, true> : public PropertyBase<ClassType, OffsetHolder> { 0127 public: 0128 inline operator auto() const 0129 { 0130 return primitive_value<PropType>::fromJni(this->handle().template getField<typename primitive_value<PropType>::JniType>(Jni::typeName<NameHolder>())); 0131 } 0132 inline Property& operator=(PropType value) 0133 { 0134 this->handle().setField(Jni::typeName<NameHolder>(), primitive_value<PropType>::toJni(value)); 0135 return *this; 0136 } 0137 }; 0138 0139 // TODO KF6: can be replaced by QT_WARNING_DISABLE_INVALID_OFFSETOF 0140 #if defined(Q_CC_CLANG) 0141 #define JNI_WARNING_DISABLE_INVALID_OFFSETOF QT_WARNING_DISABLE_CLANG("-Winvalid-offsetof") 0142 #elif defined(Q_CC_GNU) 0143 #define JNI_WARNING_DISABLE_INVALID_OFFSETOF QT_WARNING_DISABLE_GCC("-Winvalid-offsetof") 0144 #else 0145 #define JNI_WARNING_DISABLE_INVALID_OFFSETOF 0146 #endif 0147 0148 /** @endcond */ 0149 } 0150 0151 /** 0152 * Wrap a static final property. 0153 * This will add a public static member named @p name to the current class. This member defines an 0154 * implicit conversion operator which will trigger the corresponding a JNI read operation. 0155 * Can only be placed in classes with a @c JNI_OBJECT. 0156 * 0157 * @note Make sure to access this member with a specific type, assigning to an @c auto variable will 0158 * copy the wrapper type, not read the property value. 0159 * 0160 * @param type The data type of the property. 0161 * @param name The name of the property. 0162 */ 0163 #define JNI_CONSTANT(type, name) \ 0164 private: \ 0165 struct _jni_ ## name ## __NameHolder { static constexpr const char* jniName() { return "" #name; } }; \ 0166 public: \ 0167 static inline const KAndroidExtras::Internal::StaticProperty<type, _jni_ThisType, _jni_ ## name ## __NameHolder, Jni::is_primitive_type<type>::value> name; 0168 0169 /** 0170 * Wrap a member property. 0171 * This will add a public zero-size member named @p name to the current class. This member defines an 0172 * implicit conversion operator which will trigger the corresponding a JNI read operation, as well 0173 * as an overloaded assignment operator for the corresponding write operation. 0174 * Can only be placed in classes with a @c JNI_OBJECT. 0175 * 0176 * @note Make sure to access this member with a specific type, assigning to an @c auto variable will 0177 * copy the wrapper type, not read the property value. 0178 * 0179 * @param type The data type of the property. 0180 * @param name The name of the property. 0181 */ 0182 #define JNI_PROPERTY(type, name) \ 0183 private: \ 0184 struct _jni_ ## name ## __NameHolder { static constexpr const char* jniName() { return "" #name; } }; \ 0185 struct _jni_ ## name ## __OffsetHolder { \ 0186 static constexpr std::size_t offset() { \ 0187 QT_WARNING_PUSH JNI_WARNING_DISABLE_INVALID_OFFSETOF \ 0188 return offsetof(_jni_ThisType, name); \ 0189 QT_WARNING_POP \ 0190 } \ 0191 }; \ 0192 friend class KAndroidExtras::Internal::PropertyBase<_jni_ThisType, _jni_ ## name ## __OffsetHolder>; \ 0193 public: \ 0194 [[no_unique_address]] KAndroidExtras::Internal::Property<type, _jni_ThisType, _jni_ ## name ## __NameHolder, _jni_ ## name ## __OffsetHolder, KAndroidExtras::Jni::is_primitive_type<type>::value> name; 0195 } 0196 0197 #endif // KANDROIDEXTRAS_JNIPROPERTIES_H