diff options
-rw-r--r-- | src/corelib/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qjnienvironment.h | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qjniobject.h | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qjnitypes.h | 321 | ||||
-rw-r--r-- | src/corelib/kernel/qjnitypes_impl.h | 329 |
5 files changed, 339 insertions, 317 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index c638266256..8578afc61d 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -999,7 +999,7 @@ qt_internal_extend_target(Core CONDITION ANDROID SOURCES io/qstandardpaths_android.cpp io/qstorageinfo_linux.cpp - kernel/qjnitypes.h + kernel/qjnitypes.h kernel/qjnitypes_impl.h kernel/qjnienvironment.cpp kernel/qjnienvironment.h kernel/qjniobject.cpp kernel/qjniobject.h kernel/qjnihelpers.cpp kernel/qjnihelpers_p.h diff --git a/src/corelib/kernel/qjnienvironment.h b/src/corelib/kernel/qjnienvironment.h index f7ffa836c2..2121ceb6fe 100644 --- a/src/corelib/kernel/qjnienvironment.h +++ b/src/corelib/kernel/qjnienvironment.h @@ -8,7 +8,7 @@ #if defined(Q_QDOC) || defined(Q_OS_ANDROID) #include <jni.h> -#include <QtCore/qjnitypes.h> +#include <QtCore/qjnitypes_impl.h> QT_BEGIN_NAMESPACE diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h index 75c896a728..de73676630 100644 --- a/src/corelib/kernel/qjniobject.h +++ b/src/corelib/kernel/qjniobject.h @@ -9,7 +9,6 @@ #if defined(Q_QDOC) || defined(Q_OS_ANDROID) #include <jni.h> #include <QtCore/qjnienvironment.h> -#include <QtCore/qjnitypes.h> QT_BEGIN_NAMESPACE @@ -42,7 +41,6 @@ public: std::forward<Args>(args)...) {} QJniObject(jobject globalRef); - inline QJniObject(QtJniTypes::Object wrapper) noexcept : QJniObject(jobject(wrapper)) {} ~QJniObject(); template<typename Class, typename ...Args> diff --git a/src/corelib/kernel/qjnitypes.h b/src/corelib/kernel/qjnitypes.h index 067504c41d..72d6f2783c 100644 --- a/src/corelib/kernel/qjnitypes.h +++ b/src/corelib/kernel/qjnitypes.h @@ -4,330 +4,25 @@ #ifndef QJNITYPES_H #define QJNITYPES_H -#include <QtCore/qglobal.h> -#include <QtCore/q20type_traits.h> - #if defined(Q_QDOC) || defined(Q_OS_ANDROID) -#include <jni.h> + +#include <QtCore/qjnitypes_impl.h> +#include <QtCore/qjniobject.h> QT_BEGIN_NAMESPACE namespace QtJniTypes { - -// a constexpr type for string literals of any character width, aware of the length -// of the string. -template<size_t N_WITH_NULL, typename BaseType = char> -struct String -{ - BaseType m_data[N_WITH_NULL] = {}; - - constexpr String() noexcept {} - // Can be instantiated (only) with a string literal - constexpr explicit String(const BaseType (&data)[N_WITH_NULL]) noexcept - { - for (size_t i = 0; i < N_WITH_NULL - 1; ++i) - m_data[i] = data[i]; - } - - constexpr BaseType at(size_t i) const { return m_data[i]; } - constexpr BaseType operator[](size_t i) const { return at(i); } - static constexpr size_t size() noexcept { return N_WITH_NULL; } - constexpr operator const BaseType *() const noexcept { return m_data; } - constexpr const BaseType *data() const noexcept { return m_data; } - template<size_t N2_WITH_NULL> - constexpr bool startsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept - { - if constexpr (N2_WITH_NULL > N_WITH_NULL) { - return false; - } else { - for (size_t i = 0; i < N2_WITH_NULL - 1; ++i) { - if (m_data[i] != lit[i]) - return false; - } - } - return true; - } - constexpr bool startsWith(BaseType c) const noexcept - { - return N_WITH_NULL > 1 && m_data[0] == c; - } - template<size_t N2_WITH_NULL> - constexpr bool endsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept - { - if constexpr (N2_WITH_NULL > N_WITH_NULL) { - return false; - } else { - for (size_t i = 0; i < N2_WITH_NULL; ++i) { - if (m_data[N_WITH_NULL - i - 1] != lit[N2_WITH_NULL - i - 1]) - return false; - } - } - return true; - } - constexpr bool endsWith(BaseType c) const noexcept - { - return N_WITH_NULL > 1 && m_data[N_WITH_NULL - 2] == c; - } - - template<size_t N2_WITH_NULL> - friend inline constexpr bool operator==(const String<N_WITH_NULL> &lhs, - const String<N2_WITH_NULL> &rhs) noexcept - { - if constexpr (N_WITH_NULL != N2_WITH_NULL) { - return false; - } else { - for (size_t i = 0; i < N_WITH_NULL - 1; ++i) { - if (lhs.at(i) != rhs.at(i)) - return false; - } - } - return true; - } - - template<size_t N2_WITH_NULL> - friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs, - const String<N2_WITH_NULL> &rhs) noexcept - { - return !operator==(lhs, rhs); - } - - template<size_t N2_WITH_NULL> - friend inline constexpr bool operator==(const String<N_WITH_NULL> &lhs, - const BaseType (&rhs)[N2_WITH_NULL]) noexcept - { - return operator==(lhs, String<N2_WITH_NULL>(rhs)); - } - template<size_t N2_WITH_NULL> - friend inline constexpr bool operator==(const BaseType (&lhs)[N2_WITH_NULL], - const String<N_WITH_NULL> &rhs) noexcept - { - return operator==(String<N2_WITH_NULL>(lhs), rhs); - } - - template<size_t N2_WITH_NULL> - friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs, - const BaseType (&rhs)[N2_WITH_NULL]) noexcept - { - return operator!=(lhs, String<N2_WITH_NULL>(rhs)); - } - template<size_t N2_WITH_NULL> - friend inline constexpr bool operator!=(const BaseType (&lhs)[N2_WITH_NULL], - const String<N_WITH_NULL> &rhs) noexcept - { - return operator!=(String<N2_WITH_NULL>(lhs), rhs); - } - - template<size_t N2_WITH_NULL> - friend inline constexpr auto operator+(const String<N_WITH_NULL> &lhs, - const String<N2_WITH_NULL> &rhs) noexcept - { - char data[N_WITH_NULL + N2_WITH_NULL - 1] = {}; - for (size_t i = 0; i < N_WITH_NULL - 1; ++i) - data[i] = lhs[i]; - for (size_t i = 0; i < N2_WITH_NULL - 1; ++i) - data[N_WITH_NULL - 1 + i] = rhs[i]; - return String<N_WITH_NULL + N2_WITH_NULL - 1>(data); - } -}; - - -// Helper types that allow us to disable variadic overloads that would conflict -// with overloads that take a const char*. -template<typename T, size_t N = 0> struct IsStringType : std::false_type {}; -template<> struct IsStringType<const char*, 0> : std::true_type {}; -template<size_t N> struct IsStringType<String<N>> : std::true_type {}; -template<size_t N> struct IsStringType<const char[N]> : std::true_type {}; - -template<bool flag = false> -static void staticAssertTypeMismatch() -{ - static_assert(flag, "The used type is not supported by this template call. " - "Use a JNI based type instead."); -} - -template<typename T> -constexpr auto typeSignature() -{ - if constexpr (std::is_array_v<T>) { - using UnderlyingType = typename std::remove_extent_t<T>; - static_assert(!std::is_array_v<UnderlyingType>, - "typeSignature() does not handle multi-dimensional arrays"); - return String("[") + typeSignature<UnderlyingType>(); - } else if constexpr (std::is_same_v<T, jobject>) { - return String("Ljava/lang/Object;"); - } else if constexpr (std::is_same_v<T, jclass>) { - return String("Ljava/lang/Class;"); - } else if constexpr (std::is_same_v<T, jstring>) { - return String("Ljava/lang/String;"); - } else if constexpr (std::is_same_v<T, jobjectArray>) { - return String("[Ljava/lang/Object;"); - } else if constexpr (std::is_same_v<T, jthrowable>) { - return String("Ljava/lang/Throwable;"); - } else if constexpr (std::is_same_v<T, jbooleanArray>) { - return String("[Z"); - } else if constexpr (std::is_same_v<T, jbyteArray>) { - return String("[B"); - } else if constexpr (std::is_same_v<T, jshortArray>) { - return String("[S"); - } else if constexpr (std::is_same_v<T, jintArray>) { - return String("[I"); - } else if constexpr (std::is_same_v<T, jlongArray>) { - return String("[J"); - } else if constexpr (std::is_same_v<T, jfloatArray>) { - return String("[F"); - } else if constexpr (std::is_same_v<T, jdoubleArray>) { - return String("[D"); - } else if constexpr (std::is_same_v<T, jcharArray>) { - return String("[C"); - } else if constexpr (std::is_same_v<T, jboolean>) { - return String("Z"); - } else if constexpr (std::is_same_v<T, bool>) { - return String("Z"); - } else if constexpr (std::is_same_v<T, jbyte>) { - return String("B"); - } else if constexpr (std::is_same_v<T, jchar>) { - return String("C"); - } else if constexpr (std::is_same_v<T, char>) { - return String("C"); - } else if constexpr (std::is_same_v<T, jshort>) { - return String("S"); - } else if constexpr (std::is_same_v<T, short>) { - return String("S"); - } else if constexpr (std::is_same_v<T, jint>) { - return String("I"); - } else if constexpr (std::is_same_v<T, int>) { - return String("I"); - } else if constexpr (std::is_same_v<T, uint>) { - return String("I"); - } else if constexpr (std::is_same_v<T, jlong>) { - return String("J"); - } else if constexpr (std::is_same_v<T, long>) { - return String("J"); - } else if constexpr (std::is_same_v<T, jfloat>) { - return String("F"); - } else if constexpr (std::is_same_v<T, float>) { - return String("F"); - } else if constexpr (std::is_same_v<T, jdouble>) { - return String("D"); - } else if constexpr (std::is_same_v<T, double>) { - return String("D"); - } else if constexpr (std::is_same_v<T, void>) { - return String("V"); - } - - // else: The return type becomes void, indicating that the typeSignature - // template is not implemented for the respective type. We use this to - // detect invalid types in the ValidSignatureTypes and ValidFieldType - // predicates below. -} - -template<bool flag = false> -static void staticAssertClassNotRegistered() -{ - static_assert(flag, "Class not registered, use Q_DECLARE_JNI_CLASS"); -} - -template<typename T> -constexpr auto className() -{ - if constexpr (std::is_same_v<T, jstring>) - return String("java/lang/String"); - else - staticAssertClassNotRegistered(); -} - -template<typename T> -static constexpr bool isPrimitiveType() -{ - return typeSignature<T>().size() == 2; -} - -template<typename T> -static constexpr bool isObjectType() -{ - if constexpr (std::is_convertible_v<T, jobject>) { - return true; - } else { - constexpr auto signature = typeSignature<T>(); - return (signature.startsWith('L') || signature.startsWith('[')) - && signature.endsWith(';'); - } -} - -template<typename T> -static constexpr bool isArrayType() -{ - constexpr auto signature = typeSignature<T>(); - return signature.startsWith('['); -} - -template<typename T> -static constexpr void assertObjectType() -{ - static_assert(isObjectType<T>(), - "Type needs to be a JNI object type (convertible to jobject, or with " - "an object type signature registered)!"); -} - -// A set of types is valid if typeSignature is implemented for all of them -template<typename ...Types> -constexpr bool ValidSignatureTypesDetail = !std::disjunction<std::is_same< - decltype(QtJniTypes::typeSignature<Types>()), - void>..., - IsStringType<Types>...>::value; -template<typename ...Types> -using ValidSignatureTypes = std::enable_if_t< - ValidSignatureTypesDetail<q20::remove_cvref_t<Types>...>, bool>; - -template<typename Type> -constexpr bool ValidFieldTypeDetail = isObjectType<Type>() || isPrimitiveType<Type>(); -template<typename Type> -using ValidFieldType = std::enable_if_t< - ValidFieldTypeDetail<q20::remove_cvref_t<Type>>, bool>; - - -template<typename R, typename ...Args, ValidSignatureTypes<R, Args...> = true> -static constexpr auto methodSignature() -{ - return (String("(") + - ... + typeSignature<q20::remove_cvref_t<Args>>()) - + String(")") - + typeSignature<R>(); -} - -template<typename T, ValidSignatureTypes<T> = true> -static constexpr auto fieldSignature() -{ - return QtJniTypes::typeSignature<T>(); -} - -template<typename ...Args, ValidSignatureTypes<Args...> = true> -static constexpr auto constructorSignature() -{ - return methodSignature<void, Args...>(); -} - -template<typename Ret, typename ...Args, ValidSignatureTypes<Ret, Args...> = true> -static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jobject, Args...)) -{ - return methodSignature<Ret, Args...>(); -} - -template<typename Ret, typename ...Args, ValidSignatureTypes<Ret, Args...> = true> -static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jclass, Args...)) -{ - return methodSignature<Ret, Args...>(); -} - // A generic thin wrapper around jobject, convertible to jobject. // We need this as a baseclass so that QJniObject can be implicitly -// constructed from the various subclasses - we can't provide an -// operator QJniObject() here as the class is not declared. +// constructed from the various subclasses. We can also pass instances +// of this type (or of any of the generated subclasses) as if it was +// a jobject. struct Object { jobject _object; constexpr operator jobject() const { return _object; } + operator QJniObject() const { return QJniObject(_object); } }; } // namespace QtJniTypes @@ -402,6 +97,6 @@ static const JNINativeMethod Method##_method = { \ QT_END_NAMESPACE -#endif +#endif // defined(Q_QDOC) || defined(Q_OS_ANDROID) #endif // QJNITYPES_H diff --git a/src/corelib/kernel/qjnitypes_impl.h b/src/corelib/kernel/qjnitypes_impl.h new file mode 100644 index 0000000000..a7a3a30b2a --- /dev/null +++ b/src/corelib/kernel/qjnitypes_impl.h @@ -0,0 +1,329 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QJNITYPES_IMPL_H +#define QJNITYPES_IMPL_H + +#include <QtCore/qglobal.h> +#include <QtCore/q20type_traits.h> + +#if defined(Q_QDOC) || defined(Q_OS_ANDROID) +#include <jni.h> + +QT_BEGIN_NAMESPACE + +namespace QtJniTypes +{ + +// a constexpr type for string literals of any character width, aware of the length +// of the string. +template<size_t N_WITH_NULL, typename BaseType = char> +struct String +{ + BaseType m_data[N_WITH_NULL] = {}; + + constexpr String() noexcept {} + // Can be instantiated (only) with a string literal + constexpr explicit String(const BaseType (&data)[N_WITH_NULL]) noexcept + { + for (size_t i = 0; i < N_WITH_NULL - 1; ++i) + m_data[i] = data[i]; + } + + constexpr BaseType at(size_t i) const { return m_data[i]; } + constexpr BaseType operator[](size_t i) const { return at(i); } + static constexpr size_t size() noexcept { return N_WITH_NULL; } + constexpr operator const BaseType *() const noexcept { return m_data; } + constexpr const BaseType *data() const noexcept { return m_data; } + template<size_t N2_WITH_NULL> + constexpr bool startsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept + { + if constexpr (N2_WITH_NULL > N_WITH_NULL) { + return false; + } else { + for (size_t i = 0; i < N2_WITH_NULL - 1; ++i) { + if (m_data[i] != lit[i]) + return false; + } + } + return true; + } + constexpr bool startsWith(BaseType c) const noexcept + { + return N_WITH_NULL > 1 && m_data[0] == c; + } + template<size_t N2_WITH_NULL> + constexpr bool endsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept + { + if constexpr (N2_WITH_NULL > N_WITH_NULL) { + return false; + } else { + for (size_t i = 0; i < N2_WITH_NULL; ++i) { + if (m_data[N_WITH_NULL - i - 1] != lit[N2_WITH_NULL - i - 1]) + return false; + } + } + return true; + } + constexpr bool endsWith(BaseType c) const noexcept + { + return N_WITH_NULL > 1 && m_data[N_WITH_NULL - 2] == c; + } + + template<size_t N2_WITH_NULL> + friend inline constexpr bool operator==(const String<N_WITH_NULL> &lhs, + const String<N2_WITH_NULL> &rhs) noexcept + { + if constexpr (N_WITH_NULL != N2_WITH_NULL) { + return false; + } else { + for (size_t i = 0; i < N_WITH_NULL - 1; ++i) { + if (lhs.at(i) != rhs.at(i)) + return false; + } + } + return true; + } + + template<size_t N2_WITH_NULL> + friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs, + const String<N2_WITH_NULL> &rhs) noexcept + { + return !operator==(lhs, rhs); + } + + template<size_t N2_WITH_NULL> + friend inline constexpr bool operator==(const String<N_WITH_NULL> &lhs, + const BaseType (&rhs)[N2_WITH_NULL]) noexcept + { + return operator==(lhs, String<N2_WITH_NULL>(rhs)); + } + template<size_t N2_WITH_NULL> + friend inline constexpr bool operator==(const BaseType (&lhs)[N2_WITH_NULL], + const String<N_WITH_NULL> &rhs) noexcept + { + return operator==(String<N2_WITH_NULL>(lhs), rhs); + } + + template<size_t N2_WITH_NULL> + friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs, + const BaseType (&rhs)[N2_WITH_NULL]) noexcept + { + return operator!=(lhs, String<N2_WITH_NULL>(rhs)); + } + template<size_t N2_WITH_NULL> + friend inline constexpr bool operator!=(const BaseType (&lhs)[N2_WITH_NULL], + const String<N_WITH_NULL> &rhs) noexcept + { + return operator!=(String<N2_WITH_NULL>(lhs), rhs); + } + + template<size_t N2_WITH_NULL> + friend inline constexpr auto operator+(const String<N_WITH_NULL> &lhs, + const String<N2_WITH_NULL> &rhs) noexcept + { + char data[N_WITH_NULL + N2_WITH_NULL - 1] = {}; + for (size_t i = 0; i < N_WITH_NULL - 1; ++i) + data[i] = lhs[i]; + for (size_t i = 0; i < N2_WITH_NULL - 1; ++i) + data[N_WITH_NULL - 1 + i] = rhs[i]; + return String<N_WITH_NULL + N2_WITH_NULL - 1>(data); + } +}; + + +// Helper types that allow us to disable variadic overloads that would conflict +// with overloads that take a const char*. +template<typename T, size_t N = 0> struct IsStringType : std::false_type {}; +template<> struct IsStringType<const char*, 0> : std::true_type {}; +template<size_t N> struct IsStringType<String<N>> : std::true_type {}; +template<size_t N> struct IsStringType<const char[N]> : std::true_type {}; + +template<bool flag = false> +static void staticAssertTypeMismatch() +{ + static_assert(flag, "The used type is not supported by this template call. " + "Use a JNI based type instead."); +} + +template<typename T> +constexpr auto typeSignature() +{ + if constexpr (std::is_array_v<T>) { + using UnderlyingType = typename std::remove_extent_t<T>; + static_assert(!std::is_array_v<UnderlyingType>, + "typeSignature() does not handle multi-dimensional arrays"); + return String("[") + typeSignature<UnderlyingType>(); + } else if constexpr (std::is_same_v<T, jobject>) { + return String("Ljava/lang/Object;"); + } else if constexpr (std::is_same_v<T, jclass>) { + return String("Ljava/lang/Class;"); + } else if constexpr (std::is_same_v<T, jstring>) { + return String("Ljava/lang/String;"); + } else if constexpr (std::is_same_v<T, jobjectArray>) { + return String("[Ljava/lang/Object;"); + } else if constexpr (std::is_same_v<T, jthrowable>) { + return String("Ljava/lang/Throwable;"); + } else if constexpr (std::is_same_v<T, jbooleanArray>) { + return String("[Z"); + } else if constexpr (std::is_same_v<T, jbyteArray>) { + return String("[B"); + } else if constexpr (std::is_same_v<T, jshortArray>) { + return String("[S"); + } else if constexpr (std::is_same_v<T, jintArray>) { + return String("[I"); + } else if constexpr (std::is_same_v<T, jlongArray>) { + return String("[J"); + } else if constexpr (std::is_same_v<T, jfloatArray>) { + return String("[F"); + } else if constexpr (std::is_same_v<T, jdoubleArray>) { + return String("[D"); + } else if constexpr (std::is_same_v<T, jcharArray>) { + return String("[C"); + } else if constexpr (std::is_same_v<T, jboolean>) { + return String("Z"); + } else if constexpr (std::is_same_v<T, bool>) { + return String("Z"); + } else if constexpr (std::is_same_v<T, jbyte>) { + return String("B"); + } else if constexpr (std::is_same_v<T, jchar>) { + return String("C"); + } else if constexpr (std::is_same_v<T, char>) { + return String("C"); + } else if constexpr (std::is_same_v<T, jshort>) { + return String("S"); + } else if constexpr (std::is_same_v<T, short>) { + return String("S"); + } else if constexpr (std::is_same_v<T, jint>) { + return String("I"); + } else if constexpr (std::is_same_v<T, int>) { + return String("I"); + } else if constexpr (std::is_same_v<T, uint>) { + return String("I"); + } else if constexpr (std::is_same_v<T, jlong>) { + return String("J"); + } else if constexpr (std::is_same_v<T, long>) { + return String("J"); + } else if constexpr (std::is_same_v<T, jfloat>) { + return String("F"); + } else if constexpr (std::is_same_v<T, float>) { + return String("F"); + } else if constexpr (std::is_same_v<T, jdouble>) { + return String("D"); + } else if constexpr (std::is_same_v<T, double>) { + return String("D"); + } else if constexpr (std::is_same_v<T, void>) { + return String("V"); + } + + // else: The return type becomes void, indicating that the typeSignature + // template is not implemented for the respective type. We use this to + // detect invalid types in the ValidSignatureTypes and ValidFieldType + // predicates below. +} + +template<bool flag = false> +static void staticAssertClassNotRegistered() +{ + static_assert(flag, "Class not registered, use Q_DECLARE_JNI_CLASS"); +} + +template<typename T> +constexpr auto className() +{ + if constexpr (std::is_same_v<T, jstring>) + return String("java/lang/String"); + else + staticAssertClassNotRegistered(); +} + +template<typename T> +static constexpr bool isPrimitiveType() +{ + return typeSignature<T>().size() == 2; +} + +template<typename T> +static constexpr bool isObjectType() +{ + if constexpr (std::is_convertible_v<T, jobject>) { + return true; + } else { + constexpr auto signature = typeSignature<T>(); + return (signature.startsWith('L') || signature.startsWith('[')) + && signature.endsWith(';'); + } +} + +template<typename T> +static constexpr bool isArrayType() +{ + constexpr auto signature = typeSignature<T>(); + return signature.startsWith('['); +} + +template<typename T> +static constexpr void assertObjectType() +{ + static_assert(isObjectType<T>(), + "Type needs to be a JNI object type (convertible to jobject, or with " + "an object type signature registered)!"); +} + +// A set of types is valid if typeSignature is implemented for all of them +template<typename ...Types> +constexpr bool ValidSignatureTypesDetail = !std::disjunction<std::is_same< + decltype(QtJniTypes::typeSignature<Types>()), + void>..., + IsStringType<Types>...>::value; +template<typename ...Types> +using ValidSignatureTypes = std::enable_if_t< + ValidSignatureTypesDetail<q20::remove_cvref_t<Types>...>, bool>; + +template<typename Type> +constexpr bool ValidFieldTypeDetail = isObjectType<Type>() || isPrimitiveType<Type>(); +template<typename Type> +using ValidFieldType = std::enable_if_t< + ValidFieldTypeDetail<q20::remove_cvref_t<Type>>, bool>; + + +template<typename R, typename ...Args, ValidSignatureTypes<R, Args...> = true> +static constexpr auto methodSignature() +{ + return (String("(") + + ... + typeSignature<q20::remove_cvref_t<Args>>()) + + String(")") + + typeSignature<R>(); +} + +template<typename T, ValidSignatureTypes<T> = true> +static constexpr auto fieldSignature() +{ + return QtJniTypes::typeSignature<T>(); +} + +template<typename ...Args, ValidSignatureTypes<Args...> = true> +static constexpr auto constructorSignature() +{ + return methodSignature<void, Args...>(); +} + +template<typename Ret, typename ...Args, ValidSignatureTypes<Ret, Args...> = true> +static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jobject, Args...)) +{ + return methodSignature<Ret, Args...>(); +} + +template<typename Ret, typename ...Args, ValidSignatureTypes<Ret, Args...> = true> +static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jclass, Args...)) +{ + return methodSignature<Ret, Args...>(); +} + +} // namespace QtJniTypes + +QT_END_NAMESPACE + +#endif + +#endif // QJNITYPES_IMPL_H |