Compare commits
4 Commits
master
...
wip/versio
Author | SHA1 | Date |
---|---|---|
Martchus | 2138491ee5 | |
Martchus | db0082c325 | |
Martchus | 2c6c63579b | |
Martchus | 2c243c3e41 |
|
@ -1,19 +0,0 @@
|
||||||
# Number of days of inactivity before an issue becomes stale
|
|
||||||
daysUntilStale: 60
|
|
||||||
# Number of days of inactivity before a stale issue is closed
|
|
||||||
daysUntilClose: 7
|
|
||||||
# Issues with these labels will never be considered stale
|
|
||||||
exemptLabels:
|
|
||||||
- pinned
|
|
||||||
- security
|
|
||||||
- feature request
|
|
||||||
- enhancement
|
|
||||||
# Label to use when marking an issue as stale
|
|
||||||
staleLabel: stale
|
|
||||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
|
||||||
markComment: >
|
|
||||||
This issue has been automatically marked as stale because it has not had
|
|
||||||
recent activity. It will be closed if no further activity occurs. Thank you
|
|
||||||
for your contributions.
|
|
||||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
|
||||||
closeComment: false
|
|
|
@ -1,4 +1,4 @@
|
||||||
cmake_minimum_required(VERSION 3.17.0 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
|
||||||
|
|
||||||
# set metadata
|
# set metadata
|
||||||
project(reflective_rapidjson)
|
project(reflective_rapidjson)
|
||||||
|
|
62
README.md
62
README.md
|
@ -62,19 +62,18 @@ The following table shows the mapping of supported C++ types to supported JSON t
|
||||||
| iteratable lists (`std::vector`, `std::list`, ...) | array |
|
| iteratable lists (`std::vector`, `std::list`, ...) | array |
|
||||||
| sets (`std::set`, `std::unordered_set`, `std::multiset`, ...) | array |
|
| sets (`std::set`, `std::unordered_set`, `std::multiset`, ...) | array |
|
||||||
| `std::pair`, `std::tuple` | array |
|
| `std::pair`, `std::tuple` | array |
|
||||||
| `std::unique_ptr`, `std::shared_ptr`, `std::optional` | depends/null |
|
| `std::unique_ptr`, `std::shared_ptr` | depends/null |
|
||||||
| `std::map`, `std::unordered_map`, `std::multimap`, `std::unordered_multimap` | object |
|
| `std::map`, `std::unordered_map`, `std::multimap`, `std::unordered_multimap` | object |
|
||||||
| `std::variant` | object |
|
| `std::variant` | object |
|
||||||
| `JsonSerializable` | object |
|
| `JsonSerializable` | object |
|
||||||
|
|
||||||
### Remarks
|
### Remarks
|
||||||
* Raw pointers are not supported. This prevents
|
* Raw pointer are not supported. This prevents
|
||||||
forgetting to free memory which would have to be allocated when deserializing.
|
forgetting to free memory which would have to be allocated when deserializing.
|
||||||
* For the same reason `const char *` and `std::string_view` are only supported for serialization.
|
* For the same reason `const char *` and `std::string_view` are only supported for serialization.
|
||||||
* Enums are (de)serialized as their underlying integer value. When deserializing, it is currently *not* checked
|
* Enums are (de)serialized as their underlying integer value. When deserializing, it is currently *not* checked
|
||||||
whether the present integer value is a valid enumeration item.
|
whether the present integer value is a valid enumeration item.
|
||||||
* The JSON type for smart pointers and `std::optional` depends on the type the pointer/optional refers to.
|
* The JSON type for smart pointer depends on the type the pointer refers to. It can also be `null`.
|
||||||
It can also be `null` for null pointers or `std::optional` without value.
|
|
||||||
* If multiple `std::shared_ptr` instances point to the same object this object is serialized multiple times.
|
* If multiple `std::shared_ptr` instances point to the same object this object is serialized multiple times.
|
||||||
When deserializing those identical objects, it is currently not possible to share the memory (again). So each
|
When deserializing those identical objects, it is currently not possible to share the memory (again). So each
|
||||||
`std::shared_ptr` will point to its own copy. Note that this limitation is *not* present when using binary
|
`std::shared_ptr` will point to its own copy. Note that this limitation is *not* present when using binary
|
||||||
|
@ -354,54 +353,6 @@ An example for such custom (de)serialization can be found in the file
|
||||||
`json/reflector-chronoutilities.h`. It provides (de)serialization of `DateTime` and
|
`json/reflector-chronoutilities.h`. It provides (de)serialization of `DateTime` and
|
||||||
`TimeSpan` objects from the C++ utilities library mentioned under dependencies.
|
`TimeSpan` objects from the C++ utilities library mentioned under dependencies.
|
||||||
|
|
||||||
### Versioning
|
|
||||||
#### JSON (de)serializer
|
|
||||||
The JSON (de)serializer doesn't support versioning at this point. It'll simply read/write the
|
|
||||||
members present in the struct. Additional members (which were e.g. present in older/newer
|
|
||||||
versions of the struct) are ignored when reading and in consequence dropped when writing.
|
|
||||||
|
|
||||||
#### Binary (de)serializer
|
|
||||||
The binary (de)serializer supports *very* experimental versioning. Otherwise adding/removing
|
|
||||||
members is a breaking change. The versioning looks like this:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
// enable definition of the macros shown below (otherwise use long macros defined in
|
|
||||||
// `lib/versioning.h`)
|
|
||||||
#define REFLECTIVE_RAPIDJSON_SHORT_MACROS
|
|
||||||
|
|
||||||
#include <reflective_rapidjson/binary/serializable.h>
|
|
||||||
|
|
||||||
// example struct where version is *not* serialized/deserialized; defaults to version from
|
|
||||||
// outer scope when reading/writing, defaults to version 0 on top-level
|
|
||||||
struct Nested : public BinarySerializable<Nested> { //
|
|
||||||
std::uint32_t foo; // will be read/written in any case
|
|
||||||
|
|
||||||
as_of_version(3):
|
|
||||||
std::uint32_t bar; // will be read/written if outer scope version is >= 3
|
|
||||||
};
|
|
||||||
|
|
||||||
// example struct where version is serialized/deserialized; defaults to version 3 when writing
|
|
||||||
struct Example : public BinarySerializable<Example, 3> {
|
|
||||||
Nested nested; // will be read/written in any case, version is "propagated down"
|
|
||||||
std::uint32_t a, b; // will be read/written in any case
|
|
||||||
|
|
||||||
until_version(2):
|
|
||||||
std::uint32_t c, d; // will be read/written if version is <= 2
|
|
||||||
|
|
||||||
as_of_version(3):
|
|
||||||
std::uint32_t e, f; // will be read/written if version is >= 3
|
|
||||||
|
|
||||||
as_of_version(4):
|
|
||||||
std::uint32_t g; // will be read/written if version is >= 4
|
|
||||||
};
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
The version specified as template argument is also assumed to be the highest supported version.
|
|
||||||
If a higher version is encountered during deserialization, `BinaryVersionNotSupported` is thrown
|
|
||||||
and the deserialization aborted.
|
|
||||||
|
|
||||||
Note that the versioning is mostly untested at this point.
|
|
||||||
|
|
||||||
### Remarks
|
### Remarks
|
||||||
* Static member variables and member functions are currently ignored by the generator.
|
* Static member variables and member functions are currently ignored by the generator.
|
||||||
* It is currently not possible to ignore a specific member variable.
|
* It is currently not possible to ignore a specific member variable.
|
||||||
|
@ -511,7 +462,7 @@ make
|
||||||
make check
|
make check
|
||||||
# build tests but do not run them (optional, requires CppUnit)
|
# build tests but do not run them (optional, requires CppUnit)
|
||||||
make tests
|
make tests
|
||||||
# generate API documentation (optional, requires Doxygen)
|
# generate API documentation (optional, reqquires Doxygen)
|
||||||
make apidoc
|
make apidoc
|
||||||
# install header files, libraries and generator
|
# install header files, libraries and generator
|
||||||
make install DESTDIR="/temporary/install/location"
|
make install DESTDIR="/temporary/install/location"
|
||||||
|
@ -534,8 +485,3 @@ Add eg. `-j$(nproc)` to `make` arguments for using all cores.
|
||||||
|
|
||||||
These packages shows the required dependencies and commands to build in a plain way. So they might be useful for
|
These packages shows the required dependencies and commands to build in a plain way. So they might be useful for
|
||||||
making Reflective RapidJSON available under other platforms, too.
|
making Reflective RapidJSON available under other platforms, too.
|
||||||
|
|
||||||
## Copyright notice and license
|
|
||||||
Copyright © 2017-2023 Marius Kittler
|
|
||||||
|
|
||||||
All code is licensed under [GPL-2-or-later](LICENSE).
|
|
||||||
|
|
2
TODOs.md
2
TODOs.md
|
@ -29,5 +29,5 @@
|
||||||
- [x] Support `std::unique_ptr` and `std::shared_ptr`
|
- [x] Support `std::unique_ptr` and `std::shared_ptr`
|
||||||
- [x] Support `std::map` and `std::unordered_map`
|
- [x] Support `std::map` and `std::unordered_map`
|
||||||
- [ ] Support `std::any`
|
- [ ] Support `std::any`
|
||||||
- [x] Support `std::optional`
|
- [ ] Support `std::optional`
|
||||||
- [x] Support/document customized (de)serialization (eg. serialize some `DateTime` object to ISO string representation)
|
- [x] Support/document customized (de)serialization (eg. serialize some `DateTime` object to ISO string representation)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
cmake_minimum_required(VERSION 3.17.0 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
|
||||||
|
|
||||||
# metadata
|
# metadata
|
||||||
set(META_PROJECT_NAME reflective_rapidjson_generator)
|
set(META_PROJECT_NAME reflective_rapidjson_generator)
|
||||||
|
@ -60,9 +60,6 @@ endif ()
|
||||||
# also add reflective_rapidjson which is header-only but might pull additional include dirs for RapidJSON
|
# also add reflective_rapidjson which is header-only but might pull additional include dirs for RapidJSON
|
||||||
list(APPEND PRIVATE_LIBRARIES "${REFLECTIVE_RAPIDJSON_TARGET_NAME}")
|
list(APPEND PRIVATE_LIBRARIES "${REFLECTIVE_RAPIDJSON_TARGET_NAME}")
|
||||||
|
|
||||||
# avoid warning "'this' pointer is null" from GCC 12 about code included from libclang
|
|
||||||
list(APPEND META_PRIVATE_COMPILE_OPTIONS "-Wno-error=nonnull")
|
|
||||||
|
|
||||||
# include modules to apply configuration
|
# include modules to apply configuration
|
||||||
include(BasicConfig)
|
include(BasicConfig)
|
||||||
include(WindowsResources)
|
include(WindowsResources)
|
||||||
|
|
|
@ -246,10 +246,6 @@ void BinarySerializationCodeGenerator::generate(std::ostream &os) const
|
||||||
// print writeCustomType method
|
// print writeCustomType method
|
||||||
os << "template <> " << visibility << " void writeCustomType<::" << relevantClass.qualifiedName
|
os << "template <> " << visibility << " void writeCustomType<::" << relevantClass.qualifiedName
|
||||||
<< ">(BinarySerializer &serializer, const ::" << relevantClass.qualifiedName << " &customObject, BinaryVersion version)\n{\n";
|
<< ">(BinarySerializer &serializer, const ::" << relevantClass.qualifiedName << " &customObject, BinaryVersion version)\n{\n";
|
||||||
os << " // write base classes\n";
|
|
||||||
for (const RelevantClass *baseClass : relevantBases) {
|
|
||||||
os << " serializer.write(static_cast<const ::" << baseClass->qualifiedName << " &>(customObject), version);\n";
|
|
||||||
}
|
|
||||||
if (!relevantClass.relevantBase.empty()) {
|
if (!relevantClass.relevantBase.empty()) {
|
||||||
os << " // write version\n"
|
os << " // write version\n"
|
||||||
" using V = Versioning<"
|
" using V = Versioning<"
|
||||||
|
@ -257,8 +253,14 @@ void BinarySerializationCodeGenerator::generate(std::ostream &os) const
|
||||||
<< ">;\n"
|
<< ">;\n"
|
||||||
" if constexpr (V::enabled) {\n"
|
" if constexpr (V::enabled) {\n"
|
||||||
" serializer.writeVariableLengthUIntBE(V::applyDefault(version));\n"
|
" serializer.writeVariableLengthUIntBE(V::applyDefault(version));\n"
|
||||||
|
" } else {\n"
|
||||||
|
" (void)version;\n"
|
||||||
" }\n";
|
" }\n";
|
||||||
}
|
}
|
||||||
|
os << " // write base classes\n";
|
||||||
|
for (const RelevantClass *baseClass : relevantBases) {
|
||||||
|
os << " serializer.write(static_cast<const ::" << baseClass->qualifiedName << " &>(customObject), version);\n";
|
||||||
|
}
|
||||||
os << " // write members\n";
|
os << " // write members\n";
|
||||||
auto mt = MemberTracking();
|
auto mt = MemberTracking();
|
||||||
for (clang::Decl *const decl : relevantClass.record->decls()) {
|
for (clang::Decl *const decl : relevantClass.record->decls()) {
|
||||||
|
@ -293,7 +295,7 @@ void BinarySerializationCodeGenerator::generate(std::ostream &os) const
|
||||||
}
|
}
|
||||||
mt.concludeCondition(os);
|
mt.concludeCondition(os);
|
||||||
if (relevantBases.empty() && !mt.membersWritten) {
|
if (relevantBases.empty() && !mt.membersWritten) {
|
||||||
os << " (void)serializer;\n (void)customObject;\n \n(void)version;";
|
os << " (void)serializer;\n (void)customObject;\n";
|
||||||
}
|
}
|
||||||
os << "}\n";
|
os << "}\n";
|
||||||
|
|
||||||
|
@ -305,22 +307,20 @@ void BinarySerializationCodeGenerator::generate(std::ostream &os) const
|
||||||
// print readCustomType method
|
// print readCustomType method
|
||||||
mt = MemberTracking();
|
mt = MemberTracking();
|
||||||
os << "template <> " << visibility << " BinaryVersion readCustomType<::" << relevantClass.qualifiedName
|
os << "template <> " << visibility << " BinaryVersion readCustomType<::" << relevantClass.qualifiedName
|
||||||
<< ">(BinaryDeserializer &deserializer, ::" << relevantClass.qualifiedName << " &customObject, BinaryVersion version)\n{\n";
|
<< ">(BinaryDeserializer &deserializer, ::" << relevantClass.qualifiedName << " &customObject)\n{\n";
|
||||||
os << " // read base classes\n";
|
|
||||||
for (const RelevantClass *baseClass : relevantBases) {
|
|
||||||
os << " deserializer.read(static_cast<::" << baseClass->qualifiedName << " &>(customObject), version);\n";
|
|
||||||
}
|
|
||||||
if (!relevantClass.relevantBase.empty()) {
|
if (!relevantClass.relevantBase.empty()) {
|
||||||
os << " // read version\n"
|
os << " // read version\n"
|
||||||
" using V = Versioning<"
|
" auto version = BinaryVersion();\n"
|
||||||
|
" if constexpr (Versioning<"
|
||||||
<< relevantClass.relevantBase
|
<< relevantClass.relevantBase
|
||||||
<< ">;\n"
|
<< ">::enabled) {\n"
|
||||||
" if constexpr (V::enabled) {\n"
|
" version = deserializer.readVariableLengthUIntBE();\n"
|
||||||
" V::assertVersion(version = deserializer.readVariableLengthUIntBE(), \""
|
|
||||||
<< relevantClass.qualifiedName
|
|
||||||
<< "\");\n"
|
|
||||||
" }\n";
|
" }\n";
|
||||||
}
|
}
|
||||||
|
os << " // read base classes\n";
|
||||||
|
for (const RelevantClass *baseClass : relevantBases) {
|
||||||
|
os << " deserializer.read(static_cast<::" << baseClass->qualifiedName << " &>(customObject));\n";
|
||||||
|
}
|
||||||
os << " // read members\n";
|
os << " // read members\n";
|
||||||
for (clang::Decl *const decl : relevantClass.record->decls()) {
|
for (clang::Decl *const decl : relevantClass.record->decls()) {
|
||||||
// check static member variables for version markers
|
// check static member variables for version markers
|
||||||
|
@ -344,7 +344,7 @@ void BinarySerializationCodeGenerator::generate(std::ostream &os) const
|
||||||
mt.writeExtraPadding(os);
|
mt.writeExtraPadding(os);
|
||||||
|
|
||||||
if (readPrivateMembers || field->getAccess() == clang::AS_public) {
|
if (readPrivateMembers || field->getAccess() == clang::AS_public) {
|
||||||
os << " deserializer.read(customObject." << field->getName() << ", version);\n";
|
os << " deserializer.read(customObject." << field->getName() << ");\n";
|
||||||
mt.membersWritten = true;
|
mt.membersWritten = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@ void JsonSerializationCodeGenerator::generate(ostream &os) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (relevantBases.empty() && !pushWritten) {
|
if (relevantBases.empty() && !pushWritten) {
|
||||||
os << " (void)reflectable;\n (void)value;\n (void)allocator;\n";
|
os << " (void)reflectable;\n (void)value;\n";
|
||||||
}
|
}
|
||||||
os << "}\n";
|
os << "}\n";
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ void JsonSerializationCodeGenerator::generate(ostream &os) const
|
||||||
os << " pull(static_cast<::" << baseClass->qualifiedName << " &>(reflectable), value, errors);\n";
|
os << " pull(static_cast<::" << baseClass->qualifiedName << " &>(reflectable), value, errors);\n";
|
||||||
}
|
}
|
||||||
os << " // set error context for current record\n"
|
os << " // set error context for current record\n"
|
||||||
" const char *previousRecord = nullptr;\n"
|
" const char *previousRecord;\n"
|
||||||
" if (errors) {\n"
|
" if (errors) {\n"
|
||||||
" previousRecord = errors->currentRecord;\n"
|
" previousRecord = errors->currentRecord;\n"
|
||||||
" errors->currentRecord = \""
|
" errors->currentRecord = \""
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
#include <clang/AST/DeclCXX.h>
|
#include <clang/AST/DeclCXX.h>
|
||||||
#include <clang/AST/DeclFriend.h>
|
#include <clang/AST/DeclFriend.h>
|
||||||
#include <clang/AST/DeclTemplate.h>
|
#include <clang/AST/DeclTemplate.h>
|
||||||
#include <clang/AST/PrettyPrinter.h>
|
|
||||||
#include <clang/AST/QualTypeNames.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
@ -96,13 +94,12 @@ void SerializationCodeGenerator::computeRelevantClass(RelevantClass &possiblyRel
|
||||||
|
|
||||||
// consider all classes inheriting from an instantiation of "JsonSerializable" relevant
|
// consider all classes inheriting from an instantiation of "JsonSerializable" relevant
|
||||||
if (const auto *const relevantBase = inheritsFromInstantiationOf(possiblyRelevantClass.record, m_qualifiedNameOfRecords)) {
|
if (const auto *const relevantBase = inheritsFromInstantiationOf(possiblyRelevantClass.record, m_qualifiedNameOfRecords)) {
|
||||||
auto policy = clang::PrintingPolicy(possiblyRelevantClass.record->getASTContext().getLangOpts());
|
cerr << "record: " << possiblyRelevantClass.qualifiedName << '\n';
|
||||||
policy.FullyQualifiedName = true;
|
for (const clang::CXXBaseSpecifier base : possiblyRelevantClass.record->bases()) {
|
||||||
policy.SuppressScope = false;
|
cerr << "base: " << base.getType().getAsString() << '\n';
|
||||||
policy.SuppressUnwrittenScope = false;
|
}
|
||||||
policy.SplitTemplateClosers = false;
|
cerr << "relevant base: " << relevantBase->getType().getAsString();
|
||||||
possiblyRelevantClass.relevantBase
|
possiblyRelevantClass.relevantBase = relevantBase->getType().getAsString();
|
||||||
= clang::TypeName::getFullyQualifiedName(relevantBase->getType(), possiblyRelevantClass.record->getASTContext(), policy, true);
|
|
||||||
possiblyRelevantClass.isRelevant = IsRelevant::Yes;
|
possiblyRelevantClass.isRelevant = IsRelevant::Yes;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ template <> void pull<::TestNamespace1::Person>(::TestNamespace1::Person &refle
|
||||||
{
|
{
|
||||||
// pull base classes
|
// pull base classes
|
||||||
// set error context for current record
|
// set error context for current record
|
||||||
const char *previousRecord = nullptr;
|
const char *previousRecord;
|
||||||
if (errors) {
|
if (errors) {
|
||||||
previousRecord = errors->currentRecord;
|
previousRecord = errors->currentRecord;
|
||||||
errors->currentRecord = "TestNamespace1::Person";
|
errors->currentRecord = "TestNamespace1::Person";
|
||||||
|
@ -39,7 +39,7 @@ template <> void pull<::TestNamespace2::ThirdPartyStruct>(::TestNamespace2::Thi
|
||||||
{
|
{
|
||||||
// pull base classes
|
// pull base classes
|
||||||
// set error context for current record
|
// set error context for current record
|
||||||
const char *previousRecord = nullptr;
|
const char *previousRecord;
|
||||||
if (errors) {
|
if (errors) {
|
||||||
previousRecord = errors->currentRecord;
|
previousRecord = errors->currentRecord;
|
||||||
errors->currentRecord = "TestNamespace2::ThirdPartyStruct";
|
errors->currentRecord = "TestNamespace2::ThirdPartyStruct";
|
||||||
|
|
|
@ -70,11 +70,6 @@ struct PointerStruct : public BinarySerializable<PointerStruct> {
|
||||||
std::shared_ptr<PointerTarget> s3;
|
std::shared_ptr<PointerTarget> s3;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief All of this is supposed to work if classes are within a namespace so let's use a namespace here.
|
|
||||||
*/
|
|
||||||
namespace SomeNamespace {
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief The PointerStruct struct is used to test the behavior of the binary (de)serialization with smart pointer.
|
* \brief The PointerStruct struct is used to test the behavior of the binary (de)serialization with smart pointer.
|
||||||
*/
|
*/
|
||||||
|
@ -93,6 +88,4 @@ as_of_version(4):
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
} // namespace SomeNamespace
|
|
||||||
|
|
||||||
#endif // REFLECTIVE_RAPIDJSON_TESTS_MORE_STRUCTS_H
|
#endif // REFLECTIVE_RAPIDJSON_TESTS_MORE_STRUCTS_H
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
cmake_minimum_required(VERSION 3.17.0 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
|
||||||
|
|
||||||
# metadata
|
# metadata
|
||||||
set(META_PROJECT_TYPE library)
|
set(META_PROJECT_TYPE library)
|
||||||
|
|
|
@ -24,17 +24,19 @@
|
||||||
namespace ReflectiveRapidJSON {
|
namespace ReflectiveRapidJSON {
|
||||||
namespace BinaryReflector {
|
namespace BinaryReflector {
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIf<IsCustomType<Type>> *>
|
template <typename Type, Traits::EnableIf<IsCustomType<Type>> *> BinaryVersion readCustomType(BinaryDeserializer &deserializer, Type &customType)
|
||||||
BinaryVersion readCustomType(BinaryDeserializer &deserializer, Type &customType, BinaryVersion version)
|
|
||||||
{
|
{
|
||||||
boost::hana::for_each(boost::hana::keys(customType), [&](auto key) { deserializer.read(boost::hana::at_key(customType, key), version); });
|
boost::hana::for_each(
|
||||||
|
boost::hana::keys(customType), [&deserializer, &customType](auto key) { deserializer.read(boost::hana::at_key(customType, key)); });
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIf<IsCustomType<Type>> *>
|
template <typename Type, Traits::EnableIf<IsCustomType<Type>> *>
|
||||||
void writeCustomType(BinarySerializer &serializer, const Type &customType, BinaryVersion version)
|
void writeCustomType(BinarySerializer &serializer, const Type &customType, BinaryVersion version)
|
||||||
{
|
{
|
||||||
boost::hana::for_each(boost::hana::keys(customType), [&](auto key) { serializer.write(boost::hana::at_key(customType, key), version); });
|
CPP_UTILITIES_UNUSED(version)
|
||||||
|
boost::hana::for_each(
|
||||||
|
boost::hana::keys(customType), [&serializer, &customType](auto key) { serializer.write(boost::hana::at_key(customType, key)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace BinaryReflector
|
} // namespace BinaryReflector
|
||||||
|
|
|
@ -16,10 +16,8 @@
|
||||||
namespace ReflectiveRapidJSON {
|
namespace ReflectiveRapidJSON {
|
||||||
namespace BinaryReflector {
|
namespace BinaryReflector {
|
||||||
|
|
||||||
template <>
|
template <> inline BinaryVersion readCustomType<CppUtilities::DateTime>(BinaryDeserializer &deserializer, CppUtilities::DateTime &dateTime)
|
||||||
inline BinaryVersion readCustomType<CppUtilities::DateTime>(BinaryDeserializer &deserializer, CppUtilities::DateTime &dateTime, BinaryVersion version)
|
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(version)
|
|
||||||
deserializer.read(dateTime.ticks());
|
deserializer.read(dateTime.ticks());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -31,10 +29,8 @@ inline void writeCustomType<CppUtilities::DateTime>(BinarySerializer &serializer
|
||||||
serializer.write(dateTime.totalTicks());
|
serializer.write(dateTime.totalTicks());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <> inline BinaryVersion readCustomType<CppUtilities::TimeSpan>(BinaryDeserializer &deserializer, CppUtilities::TimeSpan &timeSpan)
|
||||||
inline BinaryVersion readCustomType<CppUtilities::TimeSpan>(BinaryDeserializer &deserializer, CppUtilities::TimeSpan &timeSpan, BinaryVersion version)
|
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(version)
|
|
||||||
deserializer.read(timeSpan.ticks());
|
deserializer.read(timeSpan.ticks());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../traits.h"
|
#include "../traits.h"
|
||||||
#include "../versioning.h"
|
|
||||||
|
|
||||||
#include <c++utilities/conversion/conversionexception.h>
|
#include <c++utilities/conversion/conversionexception.h>
|
||||||
#include <c++utilities/io/binaryreader.h>
|
#include <c++utilities/io/binaryreader.h>
|
||||||
|
@ -17,7 +16,6 @@
|
||||||
#include <any>
|
#include <any>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
|
@ -36,6 +34,7 @@ template <typename T> struct AdaptedBinarySerializable : public Traits::Bool<fal
|
||||||
};
|
};
|
||||||
|
|
||||||
using BinaryVersion = std::uint64_t;
|
using BinaryVersion = std::uint64_t;
|
||||||
|
|
||||||
template <typename Type, BinaryVersion v = 0> struct BinarySerializable;
|
template <typename Type, BinaryVersion v = 0> struct BinarySerializable;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -47,29 +46,17 @@ namespace BinaryReflector {
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
using IsBuiltInType = Traits::Any<Traits::IsAnyOf<Type, char, std::uint8_t, bool, std::string, std::int16_t, std::uint16_t, std::int32_t,
|
using IsBuiltInType = Traits::Any<Traits::IsAnyOf<Type, char, std::uint8_t, bool, std::string, std::int16_t, std::uint16_t, std::int32_t,
|
||||||
std::uint32_t, std::int64_t, std::uint64_t, float, double>,
|
std::uint32_t, std::int64_t, std::uint64_t, float, double>,
|
||||||
Traits::IsIteratable<Type>, Traits::IsSpecializingAnyOf<Type, std::pair, std::unique_ptr, std::shared_ptr, std::optional>, std::is_enum<Type>,
|
Traits::IsIteratable<Type>, Traits::IsSpecializingAnyOf<Type, std::pair, std::unique_ptr, std::shared_ptr>, std::is_enum<Type>, IsVariant<Type>>;
|
||||||
IsVariant<Type>>;
|
|
||||||
template <typename Type> using IsCustomType = Traits::Not<IsBuiltInType<Type>>;
|
template <typename Type> using IsCustomType = Traits::Not<IsBuiltInType<Type>>;
|
||||||
|
|
||||||
class BinaryDeserializer;
|
class BinaryDeserializer;
|
||||||
class BinarySerializer;
|
class BinarySerializer;
|
||||||
|
|
||||||
/// \brief Reads \a customType via \a deserializer.
|
|
||||||
/// \remarks
|
|
||||||
/// - If \tp Type is versioned, the version is determined from the data. Otherwise \a version is assumed.
|
|
||||||
/// - The determined or specified \a version shall be passed to nested invocations.
|
|
||||||
/// \returns Returns the determined/assumed version.
|
|
||||||
template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr>
|
template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr>
|
||||||
BinaryVersion readCustomType(BinaryDeserializer &deserializer, Type &customType, BinaryVersion version = 0);
|
BinaryVersion readCustomType(BinaryDeserializer &deserializer, Type &customType);
|
||||||
|
|
||||||
/// \brief Writes \a customType via \a serializer.
|
|
||||||
/// \remarks
|
|
||||||
/// - If \tp Type is versioned, \a version is prepended to the data.
|
|
||||||
/// - The specified \a version shall be passed to nested invocations.
|
|
||||||
template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr>
|
template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr>
|
||||||
void writeCustomType(BinarySerializer &serializer, const Type &customType, BinaryVersion version = 0);
|
void writeCustomType(BinarySerializer &serializer, const Type &customType, BinaryVersion version = 0);
|
||||||
|
|
||||||
/// \brief The BinaryDeserializer class can read various data types, including custom ones, from an std::istream.
|
|
||||||
class BinaryDeserializer : public CppUtilities::BinaryReader {
|
class BinaryDeserializer : public CppUtilities::BinaryReader {
|
||||||
friend class ::BinaryReflectorTests;
|
friend class ::BinaryReflectorTests;
|
||||||
|
|
||||||
|
@ -80,7 +67,6 @@ public:
|
||||||
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> * = nullptr> void read(Type &pair);
|
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> * = nullptr> void read(Type &pair);
|
||||||
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>> * = nullptr> void read(Type &pointer);
|
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>> * = nullptr> void read(Type &pointer);
|
||||||
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>> * = nullptr> void read(Type &pointer);
|
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>> * = nullptr> void read(Type &pointer);
|
||||||
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::optional>> * = nullptr> void read(Type &pointer);
|
|
||||||
template <typename Type, Traits::EnableIf<IsArray<Type>, Traits::IsResizable<Type>> * = nullptr> void read(Type &iteratable);
|
template <typename Type, Traits::EnableIf<IsArray<Type>, Traits::IsResizable<Type>> * = nullptr> void read(Type &iteratable);
|
||||||
template <typename Type, Traits::EnableIfAny<IsMapOrHash<Type>, IsMultiMapOrHash<Type>> * = nullptr> void read(Type &iteratable);
|
template <typename Type, Traits::EnableIfAny<IsMapOrHash<Type>, IsMultiMapOrHash<Type>> * = nullptr> void read(Type &iteratable);
|
||||||
template <typename Type,
|
template <typename Type,
|
||||||
|
@ -89,14 +75,12 @@ public:
|
||||||
void read(Type &iteratable);
|
void read(Type &iteratable);
|
||||||
template <typename Type, Traits::EnableIf<std::is_enum<Type>> * = nullptr> void read(Type &enumValue);
|
template <typename Type, Traits::EnableIf<std::is_enum<Type>> * = nullptr> void read(Type &enumValue);
|
||||||
template <typename Type, Traits::EnableIf<IsVariant<Type>> * = nullptr> void read(Type &variant);
|
template <typename Type, Traits::EnableIf<IsVariant<Type>> * = nullptr> void read(Type &variant);
|
||||||
template <typename Type, Traits::EnableIf<IsBuiltInType<Type>> * = nullptr> BinaryVersion read(Type &builtInType, BinaryVersion version);
|
template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr> BinaryVersion read(Type &customType);
|
||||||
template <typename Type, Traits::EnableIf<IsCustomType<Type>> * = nullptr> BinaryVersion read(Type &customType, BinaryVersion version = 0);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::uint64_t, std::any> m_pointer;
|
std::unordered_map<std::uint64_t, std::any> m_pointer;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief The BinarySerializer class can write various data types, including custom ones, to an std::ostream.
|
|
||||||
class BinarySerializer : public CppUtilities::BinaryWriter {
|
class BinarySerializer : public CppUtilities::BinaryWriter {
|
||||||
friend class ::BinaryReflectorTests;
|
friend class ::BinaryReflectorTests;
|
||||||
|
|
||||||
|
@ -105,8 +89,7 @@ public:
|
||||||
|
|
||||||
using CppUtilities::BinaryWriter::write;
|
using CppUtilities::BinaryWriter::write;
|
||||||
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> * = nullptr> void write(const Type &pair);
|
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::pair>> * = nullptr> void write(const Type &pair);
|
||||||
template <typename Type, Traits::EnableIf<Traits::IsSpecializingAnyOf<Type, std::unique_ptr, std::optional>> * = nullptr>
|
template <typename Type, Traits::EnableIf<Traits::IsSpecializingAnyOf<Type, std::unique_ptr>> * = nullptr> void write(const Type &pointer);
|
||||||
void write(const Type &pointer);
|
|
||||||
template <typename Type, Traits::EnableIf<Traits::IsSpecializingAnyOf<Type, std::shared_ptr>> * = nullptr> void write(const Type &pointer);
|
template <typename Type, Traits::EnableIf<Traits::IsSpecializingAnyOf<Type, std::shared_ptr>> * = nullptr> void write(const Type &pointer);
|
||||||
template <typename Type, Traits::EnableIf<IsIteratableExceptString<Type>, Traits::HasSize<Type>> * = nullptr> void write(const Type &iteratable);
|
template <typename Type, Traits::EnableIf<IsIteratableExceptString<Type>, Traits::HasSize<Type>> * = nullptr> void write(const Type &iteratable);
|
||||||
template <typename Type, Traits::EnableIf<std::is_enum<Type>> * = nullptr> void write(const Type &enumValue);
|
template <typename Type, Traits::EnableIf<std::is_enum<Type>> * = nullptr> void write(const Type &enumValue);
|
||||||
|
@ -163,16 +146,6 @@ template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::optional>> *> void BinaryDeserializer::read(Type &opt)
|
|
||||||
{
|
|
||||||
if (!readBool()) {
|
|
||||||
opt.reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
opt = std::make_optional<typename Type::value_type>();
|
|
||||||
read(*opt);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIf<IsArray<Type>, Traits::IsResizable<Type>> *> void BinaryDeserializer::read(Type &iteratable)
|
template <typename Type, Traits::EnableIf<IsArray<Type>, Traits::IsResizable<Type>> *> void BinaryDeserializer::read(Type &iteratable)
|
||||||
{
|
{
|
||||||
const auto size = readVariableLengthUIntBE();
|
const auto size = readVariableLengthUIntBE();
|
||||||
|
@ -239,15 +212,9 @@ template <typename Type, Traits::EnableIf<IsVariant<Type>> *> void BinaryDeseria
|
||||||
Detail::readVariantValueByRuntimeIndex(readByte(), variant, *this);
|
Detail::readVariantValueByRuntimeIndex(readByte(), variant, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIf<IsBuiltInType<Type>> *> BinaryVersion BinaryDeserializer::read(Type &builtInType, BinaryVersion version)
|
template <typename Type, Traits::EnableIf<IsCustomType<Type>> *> BinaryVersion BinaryDeserializer::read(Type &customType)
|
||||||
{
|
{
|
||||||
read(builtInType);
|
return readCustomType(*this, customType);
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIf<IsCustomType<Type>> *> BinaryVersion BinaryDeserializer::read(Type &customType, BinaryVersion version)
|
|
||||||
{
|
|
||||||
return readCustomType(*this, customType, version);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline BinarySerializer::BinarySerializer(std::ostream *stream)
|
inline BinarySerializer::BinarySerializer(std::ostream *stream)
|
||||||
|
@ -261,12 +228,12 @@ template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::
|
||||||
write(pair.second);
|
write(pair.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type, Traits::EnableIf<Traits::IsSpecializingAnyOf<Type, std::unique_ptr, std::optional>> *>
|
template <typename Type, Traits::EnableIf<Traits::IsSpecializingAnyOf<Type, std::unique_ptr>> *> void BinarySerializer::write(const Type &pointer)
|
||||||
void BinarySerializer::write(const Type &opt)
|
|
||||||
{
|
{
|
||||||
writeBool(static_cast<bool>(opt));
|
const bool hasValue = pointer != nullptr;
|
||||||
if (opt) {
|
writeBool(hasValue);
|
||||||
write(*opt);
|
if (hasValue) {
|
||||||
|
write(*pointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,23 +14,20 @@
|
||||||
|
|
||||||
namespace ReflectiveRapidJSON {
|
namespace ReflectiveRapidJSON {
|
||||||
|
|
||||||
using BinaryVersionNotSupported = VersionNotSupported<BinaryVersion>;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief The BinarySerializable class provides the CRTP-base for (de)serializable objects.
|
* \brief The BinarySerializable class provides the CRTP-base for (de)serializable objects.
|
||||||
*/
|
*/
|
||||||
template <typename Type, BinaryVersion v> struct BinarySerializable {
|
template <typename Type, BinaryVersion v> struct BinarySerializable {
|
||||||
using VersionNotSupported = BinaryVersionNotSupported;
|
|
||||||
void toBinary(std::ostream &outputStream, BinaryVersion version = 0) const;
|
void toBinary(std::ostream &outputStream, BinaryVersion version = 0) const;
|
||||||
BinaryVersion restoreFromBinary(std::istream &inputStream);
|
BinaryVersion restoreFromBinary(std::istream &inputStream);
|
||||||
static Type fromBinary(std::istream &inputStream);
|
static Type fromBinary(std::istream &inputStream);
|
||||||
|
|
||||||
static constexpr const char *qualifiedName = "ReflectiveRapidJSON::BinarySerializable";
|
static constexpr const char *qualifiedName = "ReflectiveRapidJSON::BinarySerializable";
|
||||||
static constexpr auto version = v;
|
static constexpr auto version = v;
|
||||||
|
static constexpr auto versioningEnabled(const BinarySerializable<Type, v> &)
|
||||||
#if __cplusplus > 201707L
|
{
|
||||||
bool operator==(const BinarySerializable<Type, v> &) const = default;
|
return v != 0;
|
||||||
#endif
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Type, BinaryVersion v> inline void BinarySerializable<Type, v>::toBinary(std::ostream &outputStream, BinaryVersion version) const
|
template <typename Type, BinaryVersion v> inline void BinarySerializable<Type, v>::toBinary(std::ostream &outputStream, BinaryVersion version) const
|
||||||
|
@ -58,7 +55,8 @@ template <typename Type, BinaryVersion v> Type BinarySerializable<Type, v>::from
|
||||||
* Find out whether this is a compiler bug or a correct error message.
|
* Find out whether this is a compiler bug or a correct error message.
|
||||||
*/
|
*/
|
||||||
#define REFLECTIVE_RAPIDJSON_MAKE_BINARY_SERIALIZABLE(T) \
|
#define REFLECTIVE_RAPIDJSON_MAKE_BINARY_SERIALIZABLE(T) \
|
||||||
template <> struct ReflectiveRapidJSON::AdaptedBinarySerializable<T> : Traits::Bool<true> {}
|
template <> struct ReflectiveRapidJSON::AdaptedBinarySerializable<T> : Traits::Bool<true> { \
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ReflectiveRapidJSON
|
} // namespace ReflectiveRapidJSON
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
cmake_minimum_required(VERSION 3.17.0 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.3.0 FATAL_ERROR)
|
||||||
|
|
||||||
# prevent multiple inclusion
|
# prevent multiple inclusion
|
||||||
if (DEFINED REFLECTION_GENERATOR_MODULE_LOADED)
|
if (DEFINED REFLECTION_GENERATOR_MODULE_LOADED)
|
||||||
|
@ -44,10 +44,10 @@ if (NOT REFLECTION_GENERATOR_CLANG_RESOURCE_DIR)
|
||||||
message(FATAL_ERROR "Unable to find the clang executable to determine Clang's resource directory")
|
message(FATAL_ERROR "Unable to find the clang executable to determine Clang's resource directory")
|
||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
execute_process(
|
exec_program(
|
||||||
COMMAND ${REFLECTION_GENERATOR_CLANG_BIN} -print-resource-dir
|
${REFLECTION_GENERATOR_CLANG_BIN} ARGS
|
||||||
OUTPUT_VARIABLE REFLECTION_GENERATOR_CLANG_RESOURCE_DIR
|
-print-resource-dir
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
OUTPUT_VARIABLE REFLECTION_GENERATOR_CLANG_RESOURCE_DIR)
|
||||||
endif ()
|
endif ()
|
||||||
if (NOT REFLECTION_GENERATOR_CLANG_RESOURCE_DIR OR NOT IS_DIRECTORY "${REFLECTION_GENERATOR_CLANG_RESOURCE_DIR}")
|
if (NOT REFLECTION_GENERATOR_CLANG_RESOURCE_DIR OR NOT IS_DIRECTORY "${REFLECTION_GENERATOR_CLANG_RESOURCE_DIR}")
|
||||||
message(
|
message(
|
||||||
|
@ -87,7 +87,7 @@ endfunction ()
|
||||||
include(CMakeParseArguments)
|
include(CMakeParseArguments)
|
||||||
function (add_reflection_generator_invocation)
|
function (add_reflection_generator_invocation)
|
||||||
# parse arguments
|
# parse arguments
|
||||||
set(OPTIONAL_ARGS ERROR_RESILIENT)
|
set(OPTIONAL_ARGS)
|
||||||
set(ONE_VALUE_ARGS OUTPUT_DIRECTORY JSON_VISIBILITY BINARY_VISBILITY)
|
set(ONE_VALUE_ARGS OUTPUT_DIRECTORY JSON_VISIBILITY BINARY_VISBILITY)
|
||||||
set(MULTI_VALUE_ARGS
|
set(MULTI_VALUE_ARGS
|
||||||
INPUT_FILES
|
INPUT_FILES
|
||||||
|
@ -121,25 +121,30 @@ function (add_reflection_generator_invocation)
|
||||||
list(APPEND ARGS_CLANG_OPTIONS -I "${INCLUDE_DIR}")
|
list(APPEND ARGS_CLANG_OPTIONS -I "${INCLUDE_DIR}")
|
||||||
endforeach ()
|
endforeach ()
|
||||||
|
|
||||||
# avoid including headers from host when cross compiling
|
# add workaround for cross compiling with mingw-w64 to prevent host stdlib.h being included (not sure why specifying
|
||||||
if (CMAKE_CROSSCOMPILING)
|
# REFLECTION_GENERATOR_INCLUDE_DIRECTORIES is not enough to let it find this particular header file)
|
||||||
list(APPEND ARGS_CLANG_OPTIONS -nostdinc)
|
if (MINGW)
|
||||||
|
# find MinGW version of stdlib.h
|
||||||
|
find_file(MINGW_W64_STDLIB_H stdlib.h ${REFLECTION_GENERATOR_INCLUDE_DIRECTORIES})
|
||||||
|
if (NOT EXISTS "${MINGW_W64_STDLIB_H}")
|
||||||
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"Unable to locate MinGW version of stdlib.h. Ensure it is in REFLECTION_GENERATOR_INCLUDE_DIRECTORIES.")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
# ensure libtooling includes the MinGW version of stdlib.h rather than the host version
|
||||||
|
list(APPEND ARGS_CLANG_OPTIONS -include "${MINGW_W64_STDLIB_H}" -D_STDLIB_H # prevent processing of host stdlib.h
|
||||||
|
)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# add options to be passed to clang from the specified targets
|
# add options to be passed to clang from the specified targets
|
||||||
if (ARGS_CLANG_OPTIONS_FROM_TARGETS)
|
if (ARGS_CLANG_OPTIONS_FROM_TARGETS)
|
||||||
foreach (TARGET_NAME ${ARGS_CLANG_OPTIONS_FROM_TARGETS})
|
foreach (TARGET_NAME ${ARGS_CLANG_OPTIONS_FROM_TARGETS})
|
||||||
# set c++ standard
|
# set c++ standard
|
||||||
list(
|
list(APPEND ARGS_CLANG_OPTIONS "-std=c++$<TARGET_PROPERTY:${TARGET_NAME},CXX_STANDARD>")
|
||||||
APPEND
|
# add compile flags
|
||||||
ARGS_CLANG_OPTIONS
|
|
||||||
"$<$<BOOL:$<TARGET_PROPERTY:${TARGET_NAME},CXX_STANDARD>>:-std=c++$<TARGET_PROPERTY:${TARGET_NAME},CXX_STANDARD>>"
|
|
||||||
)
|
|
||||||
# add compile flags and options
|
|
||||||
_reflective_rapidjson_set_prop("${TARGET_NAME}" COMPILE_FLAGS)
|
_reflective_rapidjson_set_prop("${TARGET_NAME}" COMPILE_FLAGS)
|
||||||
list(APPEND ARGS_CLANG_OPTIONS "$<$<BOOL:${PROP}>:$<JOIN:${PROP},$<SEMICOLON>>>")
|
list(APPEND ARGS_CLANG_OPTIONS "$<$<BOOL:${PROP}>:$<JOIN:${PROP},$<SEMICOLON>>>")
|
||||||
_reflective_rapidjson_set_prop("${TARGET_NAME}" COMPILE_OPTIONS)
|
|
||||||
list(APPEND ARGS_CLANG_OPTIONS "$<$<BOOL:${PROP}>:$<JOIN:${PROP},$<SEMICOLON>>>")
|
|
||||||
# add compile definitions
|
# add compile definitions
|
||||||
_reflective_rapidjson_set_prop("${TARGET_NAME}" COMPILE_DEFINITIONS)
|
_reflective_rapidjson_set_prop("${TARGET_NAME}" COMPILE_DEFINITIONS)
|
||||||
list(APPEND ARGS_CLANG_OPTIONS "$<$<BOOL:${PROP}>:-D$<JOIN:${PROP},$<SEMICOLON>-D>>")
|
list(APPEND ARGS_CLANG_OPTIONS "$<$<BOOL:${PROP}>:-D$<JOIN:${PROP},$<SEMICOLON>-D>>")
|
||||||
|
@ -190,9 +195,6 @@ function (add_reflection_generator_invocation)
|
||||||
if (ARGS_BINARY_VISBILITY)
|
if (ARGS_BINARY_VISBILITY)
|
||||||
list(APPEND CLI_ARGUMENTS --binary-visibility "${ARGS_BINARY_VISBILITY}")
|
list(APPEND CLI_ARGUMENTS --binary-visibility "${ARGS_BINARY_VISBILITY}")
|
||||||
endif ()
|
endif ()
|
||||||
if (ARGS_ERROR_RESILIENT)
|
|
||||||
list(APPEND CLI_ARGUMENTS --error-resilient)
|
|
||||||
endif ()
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT "${OUTPUT_FILE}"
|
OUTPUT "${OUTPUT_FILE}"
|
||||||
COMMAND "${REFLECTION_GENERATOR_EXECUTABLE}" ARGS ${CLI_ARGUMENTS}
|
COMMAND "${REFLECTION_GENERATOR_EXECUTABLE}" ARGS ${CLI_ARGUMENTS}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../../versioning.h
|
|
|
@ -155,7 +155,6 @@ struct JsonDeserializationErrors : public std::vector<JsonDeserializationError>
|
||||||
JsonDeserializationErrors();
|
JsonDeserializationErrors();
|
||||||
|
|
||||||
template <typename ExpectedType> void reportTypeMismatch(RAPIDJSON_NAMESPACE::Type presentType);
|
template <typename ExpectedType> void reportTypeMismatch(RAPIDJSON_NAMESPACE::Type presentType);
|
||||||
template <RAPIDJSON_NAMESPACE::Type expectedType> void reportTypeMismatch(RAPIDJSON_NAMESPACE::Type presentType);
|
|
||||||
void reportArraySizeMismatch();
|
void reportArraySizeMismatch();
|
||||||
void reportConversionError(JsonType jsonType);
|
void reportConversionError(JsonType jsonType);
|
||||||
void reportUnexpectedDuplicate(JsonType jsonType);
|
void reportUnexpectedDuplicate(JsonType jsonType);
|
||||||
|
@ -221,16 +220,6 @@ template <typename ExpectedType> inline void JsonDeserializationErrors::reportTy
|
||||||
throwMaybe(ThrowOn::TypeMismatch);
|
throwMaybe(ThrowOn::TypeMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Reports a type mismatch between \tparam expectedType and \a presentType within the current context.
|
|
||||||
*/
|
|
||||||
template <RAPIDJSON_NAMESPACE::Type expectedType> inline void JsonDeserializationErrors::reportTypeMismatch(RAPIDJSON_NAMESPACE::Type presentType)
|
|
||||||
{
|
|
||||||
emplace_back(
|
|
||||||
JsonDeserializationErrorKind::TypeMismatch, jsonType(expectedType), jsonType(presentType), currentRecord, currentMember, currentIndex);
|
|
||||||
throwMaybe(ThrowOn::TypeMismatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Reports an array size mismatch.
|
* \brief Reports an array size mismatch.
|
||||||
* \todo Allow specifying expected and actual size.
|
* \todo Allow specifying expected and actual size.
|
||||||
|
|
|
@ -19,13 +19,11 @@
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <utility>
|
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
#include "./errorhandling.h"
|
#include "./errorhandling.h"
|
||||||
|
@ -83,8 +81,9 @@ inline RAPIDJSON_NAMESPACE::Document parseJsonDocFromString(const char *json, st
|
||||||
// define traits to distinguish between "built-in" types like int, std::string, std::vector, ... and custom structs/classes
|
// define traits to distinguish between "built-in" types like int, std::string, std::vector, ... and custom structs/classes
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
using IsBuiltInType = Traits::Any<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>, std::is_enum<Type>,
|
using IsBuiltInType = Traits::Any<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>, std::is_enum<Type>,
|
||||||
Traits::IsSpecializingAnyOf<Type, std::tuple, std::pair>, Traits::IsIteratable<Type>,
|
Traits::IsSpecializationOf<Type, std::tuple>, Traits::IsSpecializationOf<Type, std::pair>, Traits::IsIteratable<Type>,
|
||||||
Traits::IsSpecializingAnyOf<Type, std::unique_ptr, std::shared_ptr, std::weak_ptr, std::optional>, IsVariant<Type>>;
|
Traits::IsSpecializationOf<Type, std::unique_ptr>, Traits::IsSpecializationOf<Type, std::shared_ptr>,
|
||||||
|
Traits::IsSpecializationOf<Type, std::weak_ptr>, IsVariant<Type>>;
|
||||||
template <typename Type> using IsCustomType = Traits::Not<IsBuiltInType<Type>>;
|
template <typename Type> using IsCustomType = Traits::Not<IsBuiltInType<Type>>;
|
||||||
|
|
||||||
// define trait to check for custom structs/classes which are JSON serializable
|
// define trait to check for custom structs/classes which are JSON serializable
|
||||||
|
@ -148,24 +147,12 @@ inline void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAP
|
||||||
/*!
|
/*!
|
||||||
* \brief Pushes the specified integer/float/boolean to the specified value.
|
* \brief Pushes the specified integer/float/boolean to the specified value.
|
||||||
*/
|
*/
|
||||||
template <typename Type,
|
template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>> * = nullptr>
|
||||||
Traits::EnableIfAny<
|
|
||||||
Traits::All<std::is_integral<Type>, Traits::Not<std::is_same<Type, std::uint8_t>>, Traits::Not<std::is_same<Type, std::int8_t>>>,
|
|
||||||
std::is_floating_point<Type>> * = nullptr>
|
|
||||||
inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
|
inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
|
||||||
{
|
{
|
||||||
value.Set(reflectable, allocator);
|
value.Set(reflectable, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Pushes the specified 8-bit integer to the specified value.
|
|
||||||
*/
|
|
||||||
template <typename Type, Traits::EnableIfAny<std::is_same<Type, std::uint8_t>, std::is_same<Type, std::int8_t>> * = nullptr>
|
|
||||||
inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
|
|
||||||
{
|
|
||||||
value.Set(static_cast<int>(reflectable), allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Pushes the specified enumeration item to the specified value.
|
* \brief Pushes the specified enumeration item to the specified value.
|
||||||
*/
|
*/
|
||||||
|
@ -319,10 +306,11 @@ void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Pushes the specified unique_ptr, shared_ptr, weak_ptr or optional to the specified value.
|
* \brief Pushes the specified unique_ptr, shared_ptr or weak_ptr to the specified value.
|
||||||
*/
|
*/
|
||||||
template <typename Type,
|
template <typename Type,
|
||||||
Traits::EnableIfAny<Traits::IsSpecializingAnyOf<Type, std::unique_ptr, std::shared_ptr, std::weak_ptr, std::optional>> * = nullptr>
|
Traits::EnableIfAny<Traits::IsSpecializationOf<Type, std::unique_ptr>, Traits::IsSpecializationOf<Type, std::shared_ptr>,
|
||||||
|
Traits::IsSpecializationOf<Type, std::weak_ptr>> * = nullptr>
|
||||||
void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
|
void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
|
||||||
{
|
{
|
||||||
if (!reflectable) {
|
if (!reflectable) {
|
||||||
|
@ -491,12 +479,6 @@ void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::
|
||||||
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>> * = nullptr>
|
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>> * = nullptr>
|
||||||
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
|
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Pulls the specified \a reflectable which is an std::optional from the specified value which might be null.
|
|
||||||
*/
|
|
||||||
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::optional>> * = nullptr>
|
|
||||||
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Pulls the specified \a reflectable which is a variant from the specified value which might be null.
|
* \brief Pulls the specified \a reflectable which is a variant from the specified value which might be null.
|
||||||
*/
|
*/
|
||||||
|
@ -529,8 +511,7 @@ void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_N
|
||||||
* \brief Pulls the integer or float from the specified value which is supposed and checked to contain the right type.
|
* \brief Pulls the integer or float from the specified value which is supposed and checked to contain the right type.
|
||||||
*/
|
*/
|
||||||
template <typename Type,
|
template <typename Type,
|
||||||
Traits::EnableIf<Traits::Not<std::is_same<Type, bool>>, Traits::Not<std::is_same<Type, std::uint8_t>>,
|
Traits::EnableIf<Traits::Not<std::is_same<Type, bool>>, Traits::Any<std::is_integral<Type>, std::is_floating_point<Type>>> * = nullptr>
|
||||||
Traits::Not<std::is_same<Type, std::int8_t>>, Traits::Any<std::is_integral<Type>, std::is_floating_point<Type>>> * = nullptr>
|
|
||||||
inline void pull(
|
inline void pull(
|
||||||
Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
|
Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
|
||||||
{
|
{
|
||||||
|
@ -543,20 +524,6 @@ inline void pull(
|
||||||
reflectable = value.Is<Type>() ? value.Get<Type>() : static_cast<Type>(value.GetDouble());
|
reflectable = value.Is<Type>() ? value.Get<Type>() : static_cast<Type>(value.GetDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Pulls the integer or float from the specified value which is supposed and checked to contain the right type.
|
|
||||||
*/
|
|
||||||
template <typename Type, Traits::EnableIfAny<std::is_same<Type, std::uint8_t>, std::is_same<Type, std::int8_t>> * = nullptr>
|
|
||||||
inline void pull(
|
|
||||||
Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
pull(i, value, errors);
|
|
||||||
if (value.IsNumber()) {
|
|
||||||
reflectable = static_cast<Type>(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Pulls the boolean from the specified value which is supposed and checked to contain the right type.
|
* \brief Pulls the boolean from the specified value which is supposed and checked to contain the right type.
|
||||||
*/
|
*/
|
||||||
|
@ -701,7 +668,7 @@ void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<c
|
||||||
++index;
|
++index;
|
||||||
typename Type::value_type itemObj;
|
typename Type::value_type itemObj;
|
||||||
pull(itemObj, item, errors);
|
pull(itemObj, item, errors);
|
||||||
reflectable.emplace(std::move(itemObj));
|
reflectable.emplace(move(itemObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear error context
|
// clear error context
|
||||||
|
@ -729,7 +696,7 @@ void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<c
|
||||||
++index;
|
++index;
|
||||||
typename Type::value_type itemObj;
|
typename Type::value_type itemObj;
|
||||||
pull(itemObj, item, errors);
|
pull(itemObj, item, errors);
|
||||||
if (!reflectable.emplace(std::move(itemObj)).second) {
|
if (!reflectable.emplace(move(itemObj)).second) {
|
||||||
errors->reportUnexpectedDuplicate(JsonType::Array);
|
errors->reportUnexpectedDuplicate(JsonType::Array);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -882,20 +849,6 @@ void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::
|
||||||
pull(*reflectable, value, errors);
|
pull(*reflectable, value, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Pulls the specified \a reflectable which is an std::optional from the specified value which might be null.
|
|
||||||
*/
|
|
||||||
template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::optional>> *>
|
|
||||||
void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
|
|
||||||
{
|
|
||||||
if (value.IsNull()) {
|
|
||||||
reflectable.reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
reflectable = std::make_optional<typename Type::value_type>();
|
|
||||||
pull(*reflectable, value, errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \cond
|
/// \cond
|
||||||
namespace Detail {
|
namespace Detail {
|
||||||
template <typename Variant, std::size_t compiletimeIndex = 0>
|
template <typename Variant, std::size_t compiletimeIndex = 0>
|
||||||
|
@ -982,7 +935,7 @@ inline void pull(Type &reflectable, const char *name, const rapidjson::GenericVa
|
||||||
}
|
}
|
||||||
|
|
||||||
// set error context for current member
|
// set error context for current member
|
||||||
const char *previousMember = nullptr;
|
const char *previousMember;
|
||||||
if (errors) {
|
if (errors) {
|
||||||
previousMember = errors->currentMember;
|
previousMember = errors->currentMember;
|
||||||
errors->currentMember = name;
|
errors->currentMember = name;
|
||||||
|
|
|
@ -31,10 +31,6 @@ template <typename Type> struct JsonSerializable {
|
||||||
static Type fromJson(const std::string &json, JsonDeserializationErrors *errors = nullptr);
|
static Type fromJson(const std::string &json, JsonDeserializationErrors *errors = nullptr);
|
||||||
|
|
||||||
static constexpr const char *qualifiedName = "ReflectiveRapidJSON::JsonSerializable";
|
static constexpr const char *qualifiedName = "ReflectiveRapidJSON::JsonSerializable";
|
||||||
|
|
||||||
#if __cplusplus > 201707L
|
|
||||||
bool operator==(const JsonSerializable<Type> &) const = default;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -120,7 +116,8 @@ const JsonSerializable<Type> &as(const Type &serializable)
|
||||||
* Find out whether this is a compiler bug or a correct error message.
|
* Find out whether this is a compiler bug or a correct error message.
|
||||||
*/
|
*/
|
||||||
#define REFLECTIVE_RAPIDJSON_MAKE_JSON_SERIALIZABLE(T) \
|
#define REFLECTIVE_RAPIDJSON_MAKE_JSON_SERIALIZABLE(T) \
|
||||||
template <> struct ReflectiveRapidJSON::AdaptedJsonSerializable<T> : Traits::Bool<true> {}
|
template <> struct ReflectiveRapidJSON::AdaptedJsonSerializable<T> : Traits::Bool<true> { \
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \def The REFLECTIVE_RAPIDJSON_PUSH_PRIVATE_MEMBERS macro enables serialization of private members.
|
* \def The REFLECTIVE_RAPIDJSON_PUSH_PRIVATE_MEMBERS macro enables serialization of private members.
|
||||||
|
|
|
@ -75,9 +75,8 @@ struct ObjectWithVariantsBinary : public BinarySerializable<ObjectWithVariantsBi
|
||||||
namespace ReflectiveRapidJSON {
|
namespace ReflectiveRapidJSON {
|
||||||
namespace BinaryReflector {
|
namespace BinaryReflector {
|
||||||
|
|
||||||
template <> BinaryVersion readCustomType<TestObjectBinary>(BinaryDeserializer &deserializer, TestObjectBinary &customType, BinaryVersion version)
|
template <> BinaryVersion readCustomType<TestObjectBinary>(BinaryDeserializer &deserializer, TestObjectBinary &customType)
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(version)
|
|
||||||
deserializer.read(customType.number);
|
deserializer.read(customType.number);
|
||||||
deserializer.read(customType.number2);
|
deserializer.read(customType.number2);
|
||||||
deserializer.read(customType.numbers);
|
deserializer.read(customType.numbers);
|
||||||
|
@ -116,9 +115,8 @@ template <> void writeCustomType<TestObjectBinary>(BinarySerializer &serializer,
|
||||||
serializer.write(customType.dateTime);
|
serializer.write(customType.dateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> BinaryVersion readCustomType<NestingArrayBinary>(BinaryDeserializer &deserializer, NestingArrayBinary &customType, BinaryVersion version)
|
template <> BinaryVersion readCustomType<NestingArrayBinary>(BinaryDeserializer &deserializer, NestingArrayBinary &customType)
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(version)
|
|
||||||
deserializer.read(customType.name);
|
deserializer.read(customType.name);
|
||||||
deserializer.read(customType.testObjects);
|
deserializer.read(customType.testObjects);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -126,15 +124,12 @@ template <> BinaryVersion readCustomType<NestingArrayBinary>(BinaryDeserializer
|
||||||
|
|
||||||
template <> void writeCustomType<NestingArrayBinary>(BinarySerializer &serializer, const NestingArrayBinary &customType, BinaryVersion version)
|
template <> void writeCustomType<NestingArrayBinary>(BinarySerializer &serializer, const NestingArrayBinary &customType, BinaryVersion version)
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(version)
|
|
||||||
serializer.write(customType.name);
|
serializer.write(customType.name);
|
||||||
serializer.write(customType.testObjects);
|
serializer.write(customType.testObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <> BinaryVersion readCustomType<ObjectWithVariantsBinary>(BinaryDeserializer &deserializer, ObjectWithVariantsBinary &customType)
|
||||||
BinaryVersion readCustomType<ObjectWithVariantsBinary>(BinaryDeserializer &deserializer, ObjectWithVariantsBinary &customType, BinaryVersion version)
|
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(version)
|
|
||||||
deserializer.read(customType.someVariant);
|
deserializer.read(customType.someVariant);
|
||||||
deserializer.read(customType.anotherVariant);
|
deserializer.read(customType.anotherVariant);
|
||||||
deserializer.read(customType.yetAnotherVariant);
|
deserializer.read(customType.yetAnotherVariant);
|
||||||
|
@ -170,7 +165,6 @@ class BinaryReflectorTests : public TestFixture {
|
||||||
CPPUNIT_TEST(testSmallSharedPointer);
|
CPPUNIT_TEST(testSmallSharedPointer);
|
||||||
CPPUNIT_TEST(testBigSharedPointer);
|
CPPUNIT_TEST(testBigSharedPointer);
|
||||||
CPPUNIT_TEST(testVariant);
|
CPPUNIT_TEST(testVariant);
|
||||||
CPPUNIT_TEST(testOptional);
|
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -188,7 +182,6 @@ public:
|
||||||
void testSmallSharedPointer();
|
void testSmallSharedPointer();
|
||||||
void testBigSharedPointer();
|
void testBigSharedPointer();
|
||||||
void testVariant();
|
void testVariant();
|
||||||
void testOptional();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vector<unsigned char> m_buffer;
|
vector<unsigned char> m_buffer;
|
||||||
|
@ -273,44 +266,13 @@ void BinaryReflectorTests::tearDown()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setBuffer(std::stringstream &stream, unsigned char *buffer, std::size_t bufferSize)
|
|
||||||
{
|
|
||||||
#if defined(__GLIBCXX__) && !defined(_LIBCPP_VERSION)
|
|
||||||
stream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(buffer), static_cast<std::streamsize>(bufferSize));
|
|
||||||
#else
|
|
||||||
CPP_UTILITIES_UNUSED(stream)
|
|
||||||
CPP_UTILITIES_UNUSED(buffer)
|
|
||||||
CPP_UTILITIES_UNUSED(bufferSize)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void readBuffer(std::stringstream &stream, unsigned char *buffer, std::size_t bufferSize)
|
|
||||||
{
|
|
||||||
#if defined(__GLIBCXX__) && !defined(_LIBCPP_VERSION)
|
|
||||||
CPP_UTILITIES_UNUSED(stream)
|
|
||||||
CPP_UTILITIES_UNUSED(buffer)
|
|
||||||
CPP_UTILITIES_UNUSED(bufferSize)
|
|
||||||
#else
|
|
||||||
stream.read(reinterpret_cast<char *>(buffer), static_cast<std::streamsize>(bufferSize));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
static void writeBuffer(std::stringstream &stream, unsigned char *buffer, std::size_t bufferSize)
|
|
||||||
{
|
|
||||||
#if defined(__GLIBCXX__) && !defined(_LIBCPP_VERSION)
|
|
||||||
stream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(buffer), static_cast<std::streamsize>(bufferSize));
|
|
||||||
#else
|
|
||||||
stream.write(reinterpret_cast<const char *>(buffer), static_cast<std::streamsize>(bufferSize));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void BinaryReflectorTests::testSerializeSimpleStruct()
|
void BinaryReflectorTests::testSerializeSimpleStruct()
|
||||||
{
|
{
|
||||||
stringstream stream(ios_base::out | ios_base::binary);
|
stringstream stream(ios_base::out | ios_base::binary);
|
||||||
stream.exceptions(ios_base::failbit | ios_base::badbit);
|
stream.exceptions(ios_base::failbit | ios_base::badbit);
|
||||||
m_buffer.resize(m_expectedTestObj.size());
|
m_buffer.resize(m_expectedTestObj.size());
|
||||||
setBuffer(stream, m_buffer.data(), m_buffer.size());
|
stream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(m_buffer.data()), static_cast<streamsize>(m_buffer.size()));
|
||||||
m_testObj.toBinary(stream);
|
m_testObj.toBinary(stream);
|
||||||
readBuffer(stream, m_buffer.data(), m_buffer.size());
|
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL(m_expectedTestObj, m_buffer);
|
CPPUNIT_ASSERT_EQUAL(m_expectedTestObj, m_buffer);
|
||||||
}
|
}
|
||||||
|
@ -319,7 +281,7 @@ void BinaryReflectorTests::testDeserializeSimpleStruct()
|
||||||
{
|
{
|
||||||
stringstream stream(ios_base::in | ios_base::binary);
|
stringstream stream(ios_base::in | ios_base::binary);
|
||||||
stream.exceptions(ios_base::failbit | ios_base::badbit);
|
stream.exceptions(ios_base::failbit | ios_base::badbit);
|
||||||
writeBuffer(stream, m_expectedTestObj.data(), m_expectedTestObj.size());
|
stream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(m_expectedTestObj.data()), static_cast<streamsize>(m_expectedTestObj.size()));
|
||||||
const auto deserialized(TestObjectBinary::fromBinary(stream));
|
const auto deserialized(TestObjectBinary::fromBinary(stream));
|
||||||
assertTestObject(deserialized);
|
assertTestObject(deserialized);
|
||||||
}
|
}
|
||||||
|
@ -329,9 +291,8 @@ void BinaryReflectorTests::testSerializeNestedStruct()
|
||||||
stringstream stream(ios_base::out | ios_base::binary);
|
stringstream stream(ios_base::out | ios_base::binary);
|
||||||
stream.exceptions(ios_base::failbit | ios_base::badbit);
|
stream.exceptions(ios_base::failbit | ios_base::badbit);
|
||||||
m_buffer.resize(m_expectedNestedTestObj.size());
|
m_buffer.resize(m_expectedNestedTestObj.size());
|
||||||
setBuffer(stream, m_buffer.data(), m_buffer.size());
|
stream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(m_buffer.data()), static_cast<streamsize>(m_buffer.size()));
|
||||||
m_nestedTestObj.toBinary(stream);
|
m_nestedTestObj.toBinary(stream);
|
||||||
readBuffer(stream, m_buffer.data(), m_buffer.size());
|
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL(m_expectedNestedTestObj, m_buffer);
|
CPPUNIT_ASSERT_EQUAL(m_expectedNestedTestObj, m_buffer);
|
||||||
}
|
}
|
||||||
|
@ -340,7 +301,7 @@ void BinaryReflectorTests::testDeserializeNestedStruct()
|
||||||
{
|
{
|
||||||
stringstream stream(ios_base::in | ios_base::binary);
|
stringstream stream(ios_base::in | ios_base::binary);
|
||||||
stream.exceptions(ios_base::failbit | ios_base::badbit);
|
stream.exceptions(ios_base::failbit | ios_base::badbit);
|
||||||
writeBuffer(stream, m_expectedNestedTestObj.data(), m_expectedNestedTestObj.size());
|
stream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(m_expectedNestedTestObj.data()), static_cast<streamsize>(m_expectedNestedTestObj.size()));
|
||||||
|
|
||||||
const auto deserialized(NestingArrayBinary::fromBinary(stream));
|
const auto deserialized(NestingArrayBinary::fromBinary(stream));
|
||||||
CPPUNIT_ASSERT_EQUAL(m_nestedTestObj.name, deserialized.name);
|
CPPUNIT_ASSERT_EQUAL(m_nestedTestObj.name, deserialized.name);
|
||||||
|
@ -425,28 +386,3 @@ void BinaryReflectorTests::testVariant()
|
||||||
CPPUNIT_ASSERT_EQUAL("foo"s, get<0>(deserializedVariants.anotherVariant));
|
CPPUNIT_ASSERT_EQUAL("foo"s, get<0>(deserializedVariants.anotherVariant));
|
||||||
CPPUNIT_ASSERT_EQUAL(42, get<1>(deserializedVariants.yetAnotherVariant));
|
CPPUNIT_ASSERT_EQUAL(42, get<1>(deserializedVariants.yetAnotherVariant));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BinaryReflectorTests::testOptional()
|
|
||||||
{
|
|
||||||
// create test objects
|
|
||||||
const auto str = std::make_optional<std::string>("foo");
|
|
||||||
const auto nullStr = std::optional<std::string>();
|
|
||||||
|
|
||||||
// serialize test object
|
|
||||||
auto stream = std::stringstream(std::ios_base::in | std::ios_base::out | std::ios_base::binary);
|
|
||||||
stream.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
|
||||||
auto ser = BinaryReflector::BinarySerializer(&stream);
|
|
||||||
ser.write(str);
|
|
||||||
ser.write(nullStr);
|
|
||||||
|
|
||||||
// deserialize the object again
|
|
||||||
auto deser = BinaryReflector::BinaryDeserializer(&stream);
|
|
||||||
auto deserStr = std::optional<std::string>();
|
|
||||||
auto deserNullStr = std::optional<std::string>();
|
|
||||||
deser.read(deserStr);
|
|
||||||
deser.read(deserNullStr);
|
|
||||||
|
|
||||||
CPPUNIT_ASSERT(deserStr.has_value());
|
|
||||||
CPPUNIT_ASSERT_EQUAL("foo"s, deserStr.value());
|
|
||||||
CPPUNIT_ASSERT(!nullStr.has_value());
|
|
||||||
}
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ template <> inline void push<NestingArray>(const NestingArray &reflectable, Valu
|
||||||
template <>
|
template <>
|
||||||
inline void pull<TestObject>(TestObject &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
|
inline void pull<TestObject>(TestObject &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
|
||||||
{
|
{
|
||||||
const char *previousRecord = nullptr;
|
const char *previousRecord;
|
||||||
if (errors) {
|
if (errors) {
|
||||||
previousRecord = errors->currentRecord;
|
previousRecord = errors->currentRecord;
|
||||||
errors->currentRecord = "TestObject";
|
errors->currentRecord = "TestObject";
|
||||||
|
@ -141,7 +141,7 @@ inline void pull<TestObject>(TestObject &reflectable, const GenericValue<UTF8<ch
|
||||||
template <>
|
template <>
|
||||||
inline void pull<NestingObject>(NestingObject &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
|
inline void pull<NestingObject>(NestingObject &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
|
||||||
{
|
{
|
||||||
const char *previousRecord = nullptr;
|
const char *previousRecord;
|
||||||
if (errors) {
|
if (errors) {
|
||||||
previousRecord = errors->currentRecord;
|
previousRecord = errors->currentRecord;
|
||||||
errors->currentRecord = "NestingObject";
|
errors->currentRecord = "NestingObject";
|
||||||
|
@ -156,7 +156,7 @@ inline void pull<NestingObject>(NestingObject &reflectable, const GenericValue<U
|
||||||
template <>
|
template <>
|
||||||
inline void pull<NestingArray>(NestingArray &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
|
inline void pull<NestingArray>(NestingArray &reflectable, const GenericValue<UTF8<char>>::ConstObject &value, JsonDeserializationErrors *errors)
|
||||||
{
|
{
|
||||||
const char *previousRecord = nullptr;
|
const char *previousRecord;
|
||||||
if (errors) {
|
if (errors) {
|
||||||
previousRecord = errors->currentRecord;
|
previousRecord = errors->currentRecord;
|
||||||
errors->currentRecord = "NestingArray";
|
errors->currentRecord = "NestingArray";
|
||||||
|
@ -186,13 +186,11 @@ class JsonReflectorTests : public TestFixture {
|
||||||
CPPUNIT_TEST(testSerializeNestedObjects);
|
CPPUNIT_TEST(testSerializeNestedObjects);
|
||||||
CPPUNIT_TEST(testSerializeUniquePtr);
|
CPPUNIT_TEST(testSerializeUniquePtr);
|
||||||
CPPUNIT_TEST(testSerializeSharedPtr);
|
CPPUNIT_TEST(testSerializeSharedPtr);
|
||||||
CPPUNIT_TEST(testSerializeOptional);
|
|
||||||
CPPUNIT_TEST(testDeserializePrimitives);
|
CPPUNIT_TEST(testDeserializePrimitives);
|
||||||
CPPUNIT_TEST(testDeserializeSimpleObjects);
|
CPPUNIT_TEST(testDeserializeSimpleObjects);
|
||||||
CPPUNIT_TEST(testDeserializeNestedObjects);
|
CPPUNIT_TEST(testDeserializeNestedObjects);
|
||||||
CPPUNIT_TEST(testDeserializeUniquePtr);
|
CPPUNIT_TEST(testDeserializeUniquePtr);
|
||||||
CPPUNIT_TEST(testDeserializeSharedPtr);
|
CPPUNIT_TEST(testDeserializeSharedPtr);
|
||||||
CPPUNIT_TEST(testDeserializeOptional);
|
|
||||||
CPPUNIT_TEST(testHandlingParseError);
|
CPPUNIT_TEST(testHandlingParseError);
|
||||||
CPPUNIT_TEST(testHandlingTypeMismatch);
|
CPPUNIT_TEST(testHandlingTypeMismatch);
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
@ -207,13 +205,11 @@ public:
|
||||||
void testSerializeNestedObjects();
|
void testSerializeNestedObjects();
|
||||||
void testSerializeUniquePtr();
|
void testSerializeUniquePtr();
|
||||||
void testSerializeSharedPtr();
|
void testSerializeSharedPtr();
|
||||||
void testSerializeOptional();
|
|
||||||
void testDeserializePrimitives();
|
void testDeserializePrimitives();
|
||||||
void testDeserializeSimpleObjects();
|
void testDeserializeSimpleObjects();
|
||||||
void testDeserializeNestedObjects();
|
void testDeserializeNestedObjects();
|
||||||
void testDeserializeUniquePtr();
|
void testDeserializeUniquePtr();
|
||||||
void testDeserializeSharedPtr();
|
void testDeserializeSharedPtr();
|
||||||
void testDeserializeOptional();
|
|
||||||
void testHandlingParseError();
|
void testHandlingParseError();
|
||||||
void testHandlingTypeMismatch();
|
void testHandlingTypeMismatch();
|
||||||
|
|
||||||
|
@ -383,28 +379,6 @@ void JsonReflectorTests::testSerializeSharedPtr()
|
||||||
string(strbuf.GetString()));
|
string(strbuf.GetString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Tests serializing std::optional.
|
|
||||||
*/
|
|
||||||
void JsonReflectorTests::testSerializeOptional()
|
|
||||||
{
|
|
||||||
Document doc(kArrayType);
|
|
||||||
Document::AllocatorType &alloc = doc.GetAllocator();
|
|
||||||
doc.SetArray();
|
|
||||||
Document::Array array(doc.GetArray());
|
|
||||||
|
|
||||||
const auto str = make_optional<std::string>("foo");
|
|
||||||
const auto nullStr = std::optional<std::string>();
|
|
||||||
|
|
||||||
JsonReflector::push(str, array, alloc);
|
|
||||||
JsonReflector::push(nullStr, array, alloc);
|
|
||||||
|
|
||||||
StringBuffer strbuf;
|
|
||||||
Writer<StringBuffer> jsonWriter(strbuf);
|
|
||||||
doc.Accept(jsonWriter);
|
|
||||||
CPPUNIT_ASSERT_EQUAL("[\"foo\",null]"s, std::string(strbuf.GetString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Tests deserializing strings, numbers (int, float, double) and boolean.
|
* \brief Tests deserializing strings, numbers (int, float, double) and boolean.
|
||||||
*/
|
*/
|
||||||
|
@ -543,9 +517,6 @@ void JsonReflectorTests::testDeserializeNestedObjects()
|
||||||
CPPUNIT_ASSERT_EQUAL("test"s, nestedInVector[0].text);
|
CPPUNIT_ASSERT_EQUAL("test"s, nestedInVector[0].text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Tests deserializing std::optional.
|
|
||||||
*/
|
|
||||||
void JsonReflectorTests::testDeserializeUniquePtr()
|
void JsonReflectorTests::testDeserializeUniquePtr()
|
||||||
{
|
{
|
||||||
Document doc(kArrayType);
|
Document doc(kArrayType);
|
||||||
|
@ -590,22 +561,6 @@ void JsonReflectorTests::testDeserializeSharedPtr()
|
||||||
CPPUNIT_ASSERT_EQUAL("bar"s, obj->text);
|
CPPUNIT_ASSERT_EQUAL("bar"s, obj->text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonReflectorTests::testDeserializeOptional()
|
|
||||||
{
|
|
||||||
Document doc(kArrayType);
|
|
||||||
doc.Parse("[\"foo\",null]");
|
|
||||||
auto array = doc.GetArray().begin();
|
|
||||||
|
|
||||||
optional<string> str = "foo"s;
|
|
||||||
optional<string> nullStr;
|
|
||||||
JsonDeserializationErrors errors;
|
|
||||||
JsonReflector::pull(str, array, &errors);
|
|
||||||
CPPUNIT_ASSERT_EQUAL(0_st, errors.size());
|
|
||||||
CPPUNIT_ASSERT(str.has_value());
|
|
||||||
CPPUNIT_ASSERT_EQUAL("foo"s, *str);
|
|
||||||
CPPUNIT_ASSERT(!nullStr.has_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Tests whether RAPIDJSON_NAMESPACE::ParseResult is thrown correctly when passing invalid JSON to fromJSON().
|
* \brief Tests whether RAPIDJSON_NAMESPACE::ParseResult is thrown correctly when passing invalid JSON to fromJSON().
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -7,14 +7,20 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// define structs for testing REFLECTIVE_RAPIDJSON_TREAT_AS_…
|
// define structs for testing REFLECTIVE_RAPIDJSON_TREAT_AS_…
|
||||||
struct Foo {};
|
struct Foo {
|
||||||
struct Bar {};
|
};
|
||||||
|
struct Bar {
|
||||||
|
};
|
||||||
|
|
||||||
// define structs for testing versioning
|
// define structs for testing versioning
|
||||||
struct VersionlessBase : public ReflectiveRapidJSON::BinarySerializable<VersionlessBase> {};
|
struct VersionlessBase : public ReflectiveRapidJSON::BinarySerializable<VersionlessBase> {
|
||||||
struct VersionedDerived : public VersionlessBase, public ReflectiveRapidJSON::BinarySerializable<VersionedDerived, 1> {};
|
};
|
||||||
struct VersionedBase : public ReflectiveRapidJSON::BinarySerializable<VersionlessBase, 1> {};
|
struct VersionedDerived : public VersionlessBase, public ReflectiveRapidJSON::BinarySerializable<VersionedDerived, 1> {
|
||||||
struct VersionlessDerived : public VersionedBase, public ReflectiveRapidJSON::BinarySerializable<VersionlessDerived> {};
|
};
|
||||||
|
struct VersionedBase : public ReflectiveRapidJSON::BinarySerializable<VersionlessBase, 1> {
|
||||||
|
};
|
||||||
|
struct VersionlessDerived : public VersionedBase, public ReflectiveRapidJSON::BinarySerializable<VersionlessDerived> {
|
||||||
|
};
|
||||||
|
|
||||||
namespace ReflectiveRapidJSON {
|
namespace ReflectiveRapidJSON {
|
||||||
REFLECTIVE_RAPIDJSON_TREAT_AS_MAP_OR_HASH(Foo);
|
REFLECTIVE_RAPIDJSON_TREAT_AS_MAP_OR_HASH(Foo);
|
||||||
|
|
24
lib/traits.h
24
lib/traits.h
|
@ -16,22 +16,30 @@ namespace Traits = ::CppUtilities::Traits;
|
||||||
|
|
||||||
// define structs and macros to allow treating custom data types as std::map, std::set, ...
|
// define structs and macros to allow treating custom data types as std::map, std::set, ...
|
||||||
/// \brief \brief The TreatAsMapOrHash class allows treating custom classes as std::map or std::unordered_map.
|
/// \brief \brief The TreatAsMapOrHash class allows treating custom classes as std::map or std::unordered_map.
|
||||||
template <typename T> struct TreatAsMapOrHash : public Traits::Bool<false> {};
|
template <typename T> struct TreatAsMapOrHash : public Traits::Bool<false> {
|
||||||
|
};
|
||||||
/// \brief \brief The TreatAsMultiMapOrHash class allows treating custom classes as std::multimap or std::unordered_multimap.
|
/// \brief \brief The TreatAsMultiMapOrHash class allows treating custom classes as std::multimap or std::unordered_multimap.
|
||||||
template <typename T> struct TreatAsMultiMapOrHash : public Traits::Bool<false> {};
|
template <typename T> struct TreatAsMultiMapOrHash : public Traits::Bool<false> {
|
||||||
|
};
|
||||||
/// \brief \brief The TreatAsSet class allows treating custom classes as std::set or std::unordered_set.
|
/// \brief \brief The TreatAsSet class allows treating custom classes as std::set or std::unordered_set.
|
||||||
template <typename T> struct TreatAsSet : public Traits::Bool<false> {};
|
template <typename T> struct TreatAsSet : public Traits::Bool<false> {
|
||||||
|
};
|
||||||
/// \brief \brief The TreatAsMultiSet class allows treating custom classes as std::multiset or std::unordered_multiset.
|
/// \brief \brief The TreatAsMultiSet class allows treating custom classes as std::multiset or std::unordered_multiset.
|
||||||
template <typename T> struct TreatAsMultiSet : public Traits::Bool<false> {};
|
template <typename T> struct TreatAsMultiSet : public Traits::Bool<false> {
|
||||||
|
};
|
||||||
|
|
||||||
#define REFLECTIVE_RAPIDJSON_TREAT_AS_MAP_OR_HASH(T) \
|
#define REFLECTIVE_RAPIDJSON_TREAT_AS_MAP_OR_HASH(T) \
|
||||||
template <> struct TreatAsMapOrHash<T> : public Traits::Bool<true> {}
|
template <> struct TreatAsMapOrHash<T> : public Traits::Bool<true> { \
|
||||||
|
}
|
||||||
#define REFLECTIVE_RAPIDJSON_TREAT_AS_MULTI_MAP_OR_HASH(T) \
|
#define REFLECTIVE_RAPIDJSON_TREAT_AS_MULTI_MAP_OR_HASH(T) \
|
||||||
template <> struct TreatAsMultiMapOrHash<T> : public Traits::Bool<true> {}
|
template <> struct TreatAsMultiMapOrHash<T> : public Traits::Bool<true> { \
|
||||||
|
}
|
||||||
#define REFLECTIVE_RAPIDJSON_TREAT_AS_SET(T) \
|
#define REFLECTIVE_RAPIDJSON_TREAT_AS_SET(T) \
|
||||||
template <> struct TreatAsSet<T> : public Traits::Bool<true> {}
|
template <> struct TreatAsSet<T> : public Traits::Bool<true> { \
|
||||||
|
}
|
||||||
#define REFLECTIVE_RAPIDJSON_TREAT_AS_MULTI_SET(T) \
|
#define REFLECTIVE_RAPIDJSON_TREAT_AS_MULTI_SET(T) \
|
||||||
template <> struct TreatAsMultiSet<T> : public Traits::Bool<true> {}
|
template <> struct TreatAsMultiSet<T> : public Traits::Bool<true> { \
|
||||||
|
}
|
||||||
|
|
||||||
// define traits to check for arrays, sets and maps
|
// define traits to check for arrays, sets and maps
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
|
|
|
@ -25,11 +25,12 @@ public
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsVersioned, T::version);
|
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsVersioned, T::version);
|
||||||
|
//CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsVersioned, T::versioningEnabled(std::declval<T &>()));
|
||||||
|
|
||||||
template <typename VersionType> struct VersionNotSupported {
|
//using BinaryVersion = std::uint64_t;
|
||||||
VersionType presentVersion = 0, maxVersion = 0;
|
|
||||||
const char *record = nullptr;
|
//template <typename Type, BinaryVersion v = 0> struct BinarySerializable;
|
||||||
};
|
//CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsVersioned, static_cast<T &>(std::declval<T &>()).version);
|
||||||
|
|
||||||
template <typename Type, bool Condition = IsVersioned<Type>::value> struct Versioning {
|
template <typename Type, bool Condition = IsVersioned<Type>::value> struct Versioning {
|
||||||
static constexpr auto enabled = false;
|
static constexpr auto enabled = false;
|
||||||
|
@ -38,21 +39,10 @@ template <typename Type, bool Condition = IsVersioned<Type>::value> struct Versi
|
||||||
template <typename Type> struct Versioning<Type, true> {
|
template <typename Type> struct Versioning<Type, true> {
|
||||||
static constexpr auto enabled = Type::version != 0;
|
static constexpr auto enabled = Type::version != 0;
|
||||||
static constexpr auto serializationDefault = Type::version;
|
static constexpr auto serializationDefault = Type::version;
|
||||||
static constexpr auto maxSupported = Type::version;
|
|
||||||
static constexpr auto applyDefault(decltype(serializationDefault) version)
|
static constexpr auto applyDefault(decltype(serializationDefault) version)
|
||||||
{
|
{
|
||||||
return version ? version : serializationDefault;
|
return version ? version : serializationDefault;
|
||||||
}
|
}
|
||||||
static constexpr auto isSupported(decltype(maxSupported) version)
|
|
||||||
{
|
|
||||||
return version <= maxSupported;
|
|
||||||
}
|
|
||||||
static constexpr auto assertVersion(decltype(maxSupported) version, const char *record = nullptr)
|
|
||||||
{
|
|
||||||
if (!isSupported(version)) {
|
|
||||||
throw typename Type::VersionNotSupported({ .presentVersion = version, .maxVersion = maxSupported, .record = record });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ReflectiveRapidJSON
|
} // namespace ReflectiveRapidJSON
|
||||||
|
|
Loading…
Reference in New Issue