Commit 21a80afb authored by Volker Krause's avatar Volker Krause

Add some ideas for compile-time checked JNI signature generation

parent e92d264f
add_definitions(-DSOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
ecm_add_test(jnisignaturetest.cpp LINK_LIBRARIES Qt5::Test)
ecm_add_test(pkpassmanagertest.cpp LINK_LIBRARIES Qt5::Test itinerary)
ecm_add_test(reservationmanagertest.cpp LINK_LIBRARIES Qt5::Test itinerary)
ecm_add_test(applicationcontrollertest.cpp LINK_LIBRARIES Qt5::Test itinerary)
......
/*
Copyright (C) 2019 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <../src/kandroidextras/jnisignature.h>
#include <../src/kandroidextras/jnitypes.h>
#include <QtTest/qtest.h>
using namespace KAndroidExtras;
class JniSignatureTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testSignature()
{
QCOMPARE((const char*)Jni::signature<bool>(), "Z");
QCOMPARE((const char*)Jni::signature<void(float[])>(), "([F)V");
QCOMPARE((const char*)Jni::signature<void(java::lang::String)>(), "(Ljava/lang/String;)V");
QCOMPARE((const char*)Jni::signature<java::lang::String()>(), "()Ljava/lang/String;");
QCOMPARE((const char*)Jni::signature<android::content::Intent(java::lang::String, bool[])>(), "(Ljava/lang/String;[Z)Landroid/content/Intent;");
}
void testImplementationDetails()
{
static_assert(Internal::static_strlen("Hello!") == 6, "");
QCOMPARE(java::lang::String::jniName(), "java/lang/String");
QCOMPARE(((const char*)Internal::staticStringFromJniType<java::lang::String, std::make_index_sequence<16>>::value()), "java/lang/String");
}
};
QTEST_GUILESS_MAIN(JniSignatureTest)
#include "jnisignaturetest.moc"
/*
Copyright (C) 2019 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef KANDROIDEXTRAS_JNISIGNATURE_H
#define KANDROIDEXTRAS_JNISIGNATURE_H
#include <cstdint>
#include <utility>
namespace KAndroidExtras {
namespace Internal {
/** Compile-time concat-able string. */
template <char... String>
struct StaticString {
inline operator const char*() const
{
static const char data[] = { String..., 0 };
return data;
}
};
/** Compile-time strlen. */
constexpr inline int static_strlen(const char *str)
{
return str[0] == '\0' ? 0 : static_strlen(str + 1) + 1;
}
/** Compile-time concat for two StaticString. */
template <char... String1, char... String2>
constexpr inline auto static_concat(const StaticString<String1...>&, const StaticString<String2...>&)
{
return StaticString<String1..., String2...>();
}
/** Compile-time concapt for N StaticString. */
template <typename String1, typename String2, class... Strings>
constexpr inline auto static_concat(const String1& str1, const String2& str2, const Strings&... strs)
{
return static_concat(static_concat(str1, str2), strs...);
}
/** Conversion from const char* literals to StaticString. */
template <typename, typename> struct staticStringFromJniType;
template <typename T, std::size_t... Indexes>
struct staticStringFromJniType<T, std::index_sequence<Indexes...>>
{
typedef StaticString<T::jniName()[Indexes]...> value;
};
/** Meta function for assembling JNI signatures. */
template <typename T>
struct JniSignature
{
constexpr inline auto operator()() const
{
using namespace Internal;
return static_concat(StaticString<'L'>(), typename staticStringFromJniType<T, std::make_index_sequence<static_strlen(T::jniName())>>::value(), StaticString<';'>());
}
};
template <> struct JniSignature<bool> { constexpr inline auto operator()() const { return StaticString<'Z'>(); } };
template <> struct JniSignature<uint8_t> { constexpr inline auto operator()() const { return StaticString<'B'>(); } };
template <> struct JniSignature<char> { constexpr inline auto operator()() const { return StaticString<'C'>(); } };
template <> struct JniSignature<short> { constexpr inline auto operator()() const { return StaticString<'S'>(); } };
template <> struct JniSignature<int> { constexpr inline auto operator()() const { return StaticString<'I'>(); } };
template <> struct JniSignature<long> { constexpr inline auto operator()() const { return StaticString<'J'>(); } };
template <> struct JniSignature<float> { constexpr inline auto operator()() const { return StaticString<'F'>(); } };
template <> struct JniSignature<double> { constexpr inline auto operator()() const { return StaticString<'D'>(); } };
template <> struct JniSignature<void> { constexpr inline auto operator()() const { return StaticString<'V'>(); } };
template <typename T>
struct JniSignature<T*>
{
constexpr inline auto operator()() const
{
using namespace Internal;
return static_concat(StaticString<'['>(), JniSignature<T>()());
}
};
template <typename RetT, typename... Args>
struct JniSignature<RetT(Args...)>
{
constexpr inline auto operator()() const
{
using namespace Internal;
return static_concat(StaticString<'('>(), JniSignature<Args>()()..., StaticString<')'>(), JniSignature<RetT>()());
}
};
}
/** Helper methods to deal with JNI. */
namespace Jni
{
/** Returns the JNI signature string for the template argument types. */
template <typename... Args> constexpr __attribute__((__unused__)) Internal::JniSignature<Args...> signature = {};
}
}
#endif // KANDROIDEXTRAS_JNISIGNATURE_H
/*
Copyright (C) 2019 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef KANDROIDEXTRAS_JNITYPES_H
#define KANDROIDEXTRAS_JNITYPES_H
// determine how many elements are in __VA_ARGS__
#define PP_NARG(...) PP_NARG_(__VA_ARGS__, PP_RSEQ_N())
#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N(_1, _2, _3, _4, _5, _6, _7, N, ...) N
#define PP_RSEQ_N() 7, 6, 5, 4, 3, 2, 1, 0
// preprocessor-level token concat
#define PP_CONCAT(arg1, arg2) PP_CONCAT1(arg1, arg2)
#define PP_CONCAT1(arg1, arg2) PP_CONCAT2(arg1, arg2)
#define PP_CONCAT2(arg1, arg2) arg1##arg2
// preprocessor "iteration"
#define JNI_TYPE_1(name, type, ...) \
struct type { static constexpr const char* jniName() { return name #type; } };
#define JNI_TYPE_2(name, type, ...) \
namespace type { JNI_TYPE_1(name #type "/", __VA_ARGS__) }
#define JNI_TYPE_3(name, type, ...) \
namespace type { JNI_TYPE_2(name #type "/", __VA_ARGS__) }
#define JNI_TYPE_4(name, type, ...) \
namespace type { JNI_TYPE_3(name #type "/", __VA_ARGS__) }
#define JNI_TYPE_5(name, type, ...) \
namespace type { JNI_TYPE_4(name #type "/", __VA_ARGS__) }
#define JNI_TYPE_6(name, type, ...) \
namespace type { JNI_TYPE_5(name #type "/", __VA_ARGS__) }
#define JNI_TYPE_7(name, type, ...) \
namespace type { JNI_TYPE_6(#type "/", __VA_ARGS__) }
#define JNI_TYPE_(N, name, ...) PP_CONCAT(JNI_TYPE_, N)(name, __VA_ARGS__)
/** Macro to define Java types with their corresponding JNI signature strings. */
#define JNI_TYPE(...) JNI_TYPE_(PP_NARG(__VA_ARGS__), "", __VA_ARGS__)
// type declarations
JNI_TYPE(android, content, Intent)
JNI_TYPE(android, net, Uri)
JNI_TYPE(java, lang, String)
#endif // KANDROIDEXTRAS_JNITYPES_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment