Add Toml support using toml++ and custom preprocessor macros
Some checks failed
buildbot/IOCore-macos-builder Build done.

This commit is contained in:
S David 2024-06-10 22:06:31 -04:00
parent 98e672042d
commit a0a0df6f19
8 changed files with 254 additions and 8 deletions

10
.gitignore vendored
View File

@ -132,10 +132,14 @@ Thumbs.db
venv/ venv/
env/ env/
*.bak # Build files
CMakeCache.txt
.cache/
compile_commands.json compile_commands.json
vim-debug vim-debug
CMakeFiles/*
*.bak
.cache/
docs/ docs/
.vim/* .vim/*
build/*
.cmake/*

View File

@ -1,4 +1,3 @@
" editorconfig/local.vimrc " editorconfig/local.vimrc
" Copyright © 2023-2024 Saul D. Beniquez @{ " Copyright © 2023-2024 Saul D. Beniquez @{
" "
@ -24,7 +23,7 @@
" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE " ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
" POSSIBILITY OF SUCH DAMAGE. @} " POSSIBILITY OF SUCH DAMAGE. @}
let s:build_dir = 'debug' let s:build_dir = 'build/Debug'
let s:build_cores = 6 let s:build_cores = 6
let s:make_args = '-C '. s:build_dir . ' -j ' . s:build_cores . ' all' let s:make_args = '-C '. s:build_dir . ' -j ' . s:build_cores . ' all'

43
include/util/macros.hpp Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright © 2024 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v.2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
// clang-format off
//
#pragma once
#include <stdio.h>
#define IOCORE_EXPAND(x) x
#define IOCORE_FOREACH_1(func, param) func(param)
#define IOCORE_FOREACH_2(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_1(func, __VA_ARGS__))
#define IOCORE_FOREACH_3(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_2(func, __VA_ARGS__))
#define IOCORE_FOREACH_4(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_3(func, __VA_ARGS__))
#define IOCORE_FOREACH_5(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_4(func, __VA_ARGS__))
#define IOCORE_FOREACH_6(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_5(func, __VA_ARGS__))
#define IOCORE_FOREACH_7(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_6(func, __VA_ARGS__))
#define IOCORE_FOREACH_8(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_7(func, __VA_ARGS__))
#define IOCORE_FOREACH_9(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_8(func, __VA_ARGS__))
#define IOCORE_FOREACH_10(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_9(func, __VA_ARGS__))
#define IOCORE_FOREACH_11(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_10(func, __VA_ARGS__))
#define IOCORE_FOREACH_12(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_11(func, __VA_ARGS__))
#define IOCORE_FOREACH_13(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_12(func, __VA_ARGS__))
#define IOCORE_FOREACH_14(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_13(func, __VA_ARGS__))
#define IOCORE_FOREACH_15(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_14(func, __VA_ARGS__))
#define IOCORE_FOREACH_16(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_15(func, __VA_ARGS__))
#define IOCORE_FOREACH_17(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_16(func, __VA_ARGS__))
#define IOCORE_FOREACH_18(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_17(func, __VA_ARGS__))
#define IOCORE_FOREACH_19(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_18(func, __VA_ARGS__))
#define IOCORE_FOREACH_20(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_19(func, __VA_ARGS__))
#define IOCORE_FOREACH_21(func, param, ...) func(param); IOCORE_EXPAND(IOCORE_FOREACH_20(func, __VA_ARGS__))
#define GET_FOREACH_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,NAME,...) NAME
#define IOCORE_FOREACH(func, ...) IOCORE_EXPAND(GET_FOREACH_MACRO(__VA_ARGS__, IOCORE_FOREACH_21, IOCORE_FOREACH_20, IOCORE_FOREACH_19, IOCORE_FOREACH_18, IOCORE_FOREACH_17, IOCORE_FOREACH_16, IOCORE_FOREACH_15, IOCORE_FOREACH_14, IOCORE_FOREACH_13, IOCORE_FOREACH_12, IOCORE_FOREACH_11, IOCORE_FOREACH_10, IOCORE_FOREACH_9, IOCORE_FOREACH_8, IOCORE_FOREACH_7, IOCORE_FOREACH_6, IOCORE_FOREACH_5, IOCORE_FOREACH_4, IOCORE_FOREACH_3, IOCORE_FOREACH_2, IOCORE_FOREACH_1)(func, __VA_ARGS__))
// clang-format off
// vim: set foldmethod=syntax foldminlines=10 textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

90
include/util/toml.hpp Normal file
View File

@ -0,0 +1,90 @@
/* toml.hpp
* Copyright © 2024 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v.2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <initializer_list>
#include <utility>
#include <toml++/toml.hpp>
#include "../Exception.hpp"
#include "./macros.hpp"
#define IOCORE_TOML_TO(field) tbl.insert_or_assign(#field, obj.field);
#define IOCORE_TOML_FROM(field) \
if (!tbl.contains(#field)) { \
throw IOCore::Toml::TomlException("Missing field " #field); \
} \
\
obj.field = tbl[#field].value<decltype(obj.field)>().value();
#define IOCORE_INIT_METADATA(T) \
auto metadata = toml::table(); \
metadata.insert_or_assign("type", #T); \
tbl.insert_or_assign("General", metadata);
#define IOCORE_TOML_SERIALIZABLE(T, ...) \
const char* _class_name = #T; \
friend void to_toml_table(toml::table& tbl, const T& obj) \
{ \
IOCORE_INIT_METADATA(T) \
IOCORE_FOREACH(IOCORE_TOML_TO, __VA_ARGS__) \
} \
friend void from_toml_table(const toml::table& table, T& obj) \
{ \
auto tbl = table; \
tbl.erase("General"); \
IOCORE_FOREACH(IOCORE_TOML_FROM, __VA_ARGS__) \
}
namespace IOCore::Toml {
struct TomlException : public Exception {
TomlException()
: Exception("TOML Serialization/Deseralization Exception")
{
}
explicit TomlException(const std::string& message) : Exception(message)
{
}
~TomlException() override = default;
};
struct Table : public toml::table {
Table() = default;
Table(const toml::table& tbl) : toml::table(tbl) {}
Table(const Table& tbl) : toml::table(tbl) {}
Table(Table&& tbl) noexcept : toml::table(std::move(tbl)) {}
template<typename T>
Table(const T& obj)
{
to_toml_table(*this, obj);
}
template<typename T>
auto operator=(const T& obj) -> Table&
{
to_toml_table(*this, obj);
return *this;
}
template<typename T>
auto operator=(T&& obj) -> Table&
{
to_toml_table(*this, obj);
return *this;
}
};
}
// clang-format off
// vim: set foldmethod=marker foldmarker=@{,@} foldminlines=10 textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -4,6 +4,8 @@ add_executable(test-runner
Application.test.cpp Application.test.cpp
FileResource.test.cpp FileResource.test.cpp
Exception.test.cpp Exception.test.cpp
Util.macros.test.cpp
Util.toml.test.cpp
) )
target_include_directories(test-runner PRIVATE target_include_directories(test-runner PRIVATE

View File

@ -0,0 +1,33 @@
/* Util.test.cpp
* Copyright © 2024 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v.2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "test-utils/common.hpp"
#include "../include/util/macros.hpp"
#include "../include/util/toml.hpp"
#include <sstream>
#define PRINT_MACRO(x) buffer << #x << ": " << x << ", " << std::flush;
BEGIN_TEST_SUITE("Util.Macros")
{
TEST_CASE("IOCORE_FOREACH Macro works")
{
std::stringstream buffer;
int field1 = 10;
int field2 = 20;
IOCORE_FOREACH(PRINT_MACRO, field1, field2)
REQUIRE(buffer.str() == "field1: 10, field2: 20, ");
}
}
// clang-format off
// vim: set foldmethod=syntax foldminlines=10 textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

75
tests/Util.toml.test.cpp Normal file
View File

@ -0,0 +1,75 @@
/* Util.toml.test.cpp
* Copyright © 2024 Saul D. Beniquez
* License: Mozilla Public License v. 2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v.2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "test-utils/common.hpp"
#include "../include/util/toml.hpp"
BEGIN_TEST_SUITE("Util.Toml")
{
struct TestStruct {
int field1;
int field2;
friend void
to_toml_table(toml::table& tbl, const TestStruct& obj)
{
IOCORE_TOML_TO(field1);
IOCORE_TOML_TO(field2);
}
};
struct SerializableStruct {
int field1;
int field2;
IOCORE_TOML_SERIALIZABLE(SerializableStruct, field1, field2);
};
TEST_CASE("IOCORE_TOML_TO Macro works")
{
toml::table table;
TestStruct data;
to_toml_table(table, data);
REQUIRE(table.size() == 2);
}
TEST_CASE("IOCORE_TOML_SERIALIZABLE Macro works")
{
toml::table table;
SerializableStruct data = { 11, 22 };
SerializableStruct newdest;
to_toml_table(table, data);
from_toml_table(table, newdest);
REQUIRE(table.size() == 3);
REQUIRE(table["field1"].value<int>() == 11);
REQUIRE(table["field2"].value<int>() == 22);
REQUIRE(newdest.field1 == data.field1);
REQUIRE(newdest.field2 == data.field2);
}
TEST_CASE("Toml::Table class construction and basic operators")
{
IOCore::Toml::Table table = SerializableStruct{ 11, 22 };
REQUIRE(table.size() == 3);
REQUIRE(
table["General"]["type"].value<std::string>().value() ==
"SerializableStruct"
);
}
}
// clang-format off
// vim: set foldmethod=syntax foldminlines=10 textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -14,13 +14,13 @@
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
#pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-variable"
#define BEGIN_TEST_SUITE(name) \ #define BEGIN_TEST_SUITE(name) \
static const char* TEST_SUITE_NAME = "[" name "]"; \ static const char* TEST_SUITE_NAME = "[" name "]"; \
namespace namespace
#define TEST(testname) TEST_CASE(testname, TEST_SUITE_NAME) #define TEST(testname) TEST_CASE(testname, TEST_SUITE_NAME)
#define TEST_WITH_FIXTURE(FixtureName, testname) \ #define TEST_WITH_FIXTURE(FixtureName, testname) \
TEST_CASE_METHOD(FixtureName, testname, TEST_SUITE_NAME) TEST_CASE_METHOD(FixtureName, testname, TEST_SUITE_NAME)
#define FIXTURE_TEST(testname) TEST_WITH_FIXTURE(TestFixture, testname) #define FIXTURE_TEST(testname) TEST_WITH_FIXTURE(TestFixture, testname)