Throw exception during binary deserialization when version is not supported

This commit is contained in:
Martchus 2021-07-25 19:19:02 +02:00
parent 13428667f8
commit 44c6b8c609
4 changed files with 32 additions and 7 deletions

View File

@ -364,7 +364,7 @@ The binary (de)serializer supports *very* experimental versioning. Otherwise add
members is a breaking change. The versioning looks like this:
<pre>
// enable definition of the macros shown below (otherwise use long macros defined in
// enable definition of the macros shown below (otherwise use long macros defined in
// `lib/versioning.h`)
#define REFLECTIVE_RAPIDJSON_SHORT_MACROS
@ -379,7 +379,7 @@ as_of_version(3):
std::uint32_t bar; // will be read/written if outer scope version is &gt;= 3
};
// example struct where version is serialized/deserialized; defaults to version when writing
// example struct where version is serialized/deserialized; defaults to version 3 when writing
struct Example : public BinarySerializable&lt;Example, 3&gt; {
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
@ -395,8 +395,11 @@ as_of_version(4):
};
</pre>
A mechanism to catch unsupported versions during deserialization is yet to be implemented.
Additionally, the versioning is completely untested at this point.
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
* Static member variables and member functions are currently ignored by the generator.

View File

@ -308,10 +308,13 @@ void BinarySerializationCodeGenerator::generate(std::ostream &os) const
<< ">(BinaryDeserializer &deserializer, ::" << relevantClass.qualifiedName << " &customObject, BinaryVersion version)\n{\n";
if (!relevantClass.relevantBase.empty()) {
os << " // read version\n"
" if constexpr (Versioning<"
" using V = Versioning<"
<< relevantClass.relevantBase
<< ">::enabled) {\n"
" version = deserializer.readVariableLengthUIntBE();\n"
<< ">;\n"
" if constexpr (V::enabled) {\n"
" V::assertVersion(version = deserializer.readVariableLengthUIntBE(), \""
<< relevantClass.qualifiedName
<< "\");\n"
" }\n";
}
os << " // read base classes\n";

View File

@ -14,10 +14,13 @@
namespace ReflectiveRapidJSON {
using BinaryVersionNotSupported = VersionNotSupported<BinaryVersion>;
/*!
* \brief The BinarySerializable class provides the CRTP-base for (de)serializable objects.
*/
template <typename Type, BinaryVersion v> struct BinarySerializable {
using VersionNotSupported = BinaryVersionNotSupported;
void toBinary(std::ostream &outputStream, BinaryVersion version = 0) const;
BinaryVersion restoreFromBinary(std::istream &inputStream);
static Type fromBinary(std::istream &inputStream);

View File

@ -26,6 +26,11 @@ public
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsVersioned, T::version);
template <typename VersionType> struct VersionNotSupported {
VersionType presentVersion = 0, maxVersion = 0;
const char *record = nullptr;
};
template <typename Type, bool Condition = IsVersioned<Type>::value> struct Versioning {
static constexpr auto enabled = false;
};
@ -33,10 +38,21 @@ template <typename Type, bool Condition = IsVersioned<Type>::value> struct Versi
template <typename Type> struct Versioning<Type, true> {
static constexpr auto enabled = Type::version != 0;
static constexpr auto serializationDefault = Type::version;
static constexpr auto maxSupported = Type::version;
static constexpr auto applyDefault(decltype(serializationDefault) version)
{
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