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: members is a breaking change. The versioning looks like this:
<pre> <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`) // `lib/versioning.h`)
#define REFLECTIVE_RAPIDJSON_SHORT_MACROS #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 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; { struct Example : public BinarySerializable&lt;Example, 3&gt; {
Nested nested; // will be read/written in any case, version is "propagated down" 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 std::uint32_t a, b; // will be read/written in any case
@ -395,8 +395,11 @@ as_of_version(4):
}; };
</pre> </pre>
A mechanism to catch unsupported versions during deserialization is yet to be implemented. The version specified as template argument is also assumed to be the highest supported version.
Additionally, the versioning is completely untested at this point. 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.

View File

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

View File

@ -14,10 +14,13 @@
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);

View File

@ -26,6 +26,11 @@ public
CPP_UTILITIES_TRAITS_DEFINE_TYPE_CHECK(IsVersioned, T::version); 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 { template <typename Type, bool Condition = IsVersioned<Type>::value> struct Versioning {
static constexpr auto enabled = false; 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> { 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