From 541632fa9efcdc493500f3ffdabc39c0a1f3e320 Mon Sep 17 00:00:00 2001 From: Mindaugas Vinkelis Date: Sun, 2 Feb 2020 20:03:21 +0200 Subject: [PATCH] VIP tutorial on Version extension --- README.md | 12 ++-- doc/tutorial/README.md | 4 +- doc/tutorial/composition.md | 3 - doc/tutorial/first_extension.md | 67 +++++++++++++++++++ doc/tutorial/hello_world.md | 26 +++---- doc/tutorial/two_in_one.md | 0 examples/basic_usage.cpp | 12 ++-- examples/bit_packing.cpp | 12 ++-- examples/brief_syntax.cpp | 12 ++-- examples/composite_types.cpp | 23 +++---- examples/context_usage.cpp | 11 ++- examples/file_stream.cpp | 8 +-- examples/forward_backward_compatibility.cpp | 12 ++-- examples/inheritance.cpp | 17 ++--- examples/non_default_constructible.cpp | 12 ++-- examples/raw_pointers.cpp | 12 ++-- examples/smart_pointers_with_polymorphism.cpp | 18 +++-- 17 files changed, 148 insertions(+), 113 deletions(-) delete mode 100644 doc/tutorial/composition.md create mode 100644 doc/tutorial/first_extension.md delete mode 100644 doc/tutorial/two_in_one.md diff --git a/README.md b/README.md index 3db83f3..43b65ef 100644 --- a/README.md +++ b/README.md @@ -64,11 +64,9 @@ void serialize(S& s, MyStruct& o) { s.container4b(o.fs, 10); } -using namespace bitsery; - using Buffer = std::vector; -using OutputAdapter = OutputBufferAdapter; -using InputAdapter = InputBufferAdapter; +using OutputAdapter = bitsery::OutputBufferAdapter; +using InputAdapter = bitsery::InputBufferAdapter; int main() { MyStruct data{8941, MyEnum::V2, {15.0f, -8.5f, 0.045f}}; @@ -76,10 +74,10 @@ int main() { Buffer buffer; - auto writtenSize = quickSerialization(buffer, data); - auto state = quickDeserialization({buffer.begin(), writtenSize}, res); + auto writtenSize = bitsery::quickSerialization(buffer, data); + auto state = bitsery::quickDeserialization({buffer.begin(), writtenSize}, res); - assert(state.first == ReaderError::NoError && state.second); + assert(state.first == bitsery::ReaderError::NoError && state.second); assert(data.fs == res.fs && data.i == res.i && data.e == res.e); } ``` diff --git a/doc/tutorial/README.md b/doc/tutorial/README.md index 0f2624a..f7e7714 100644 --- a/doc/tutorial/README.md +++ b/doc/tutorial/README.md @@ -1,8 +1,8 @@ The grand plan for this tutorial is to learn how to serialize/deserialize any object efficiently in time and space, so you could focus on other, more interesting things. This tutorial will cover these main topics: -* `Hello World` write one control flow for both: serialization and deserialization. -* `Composer` efficiently compose complex serialization flows. +* [Getting started](hello_world.md) with bitsery, and serialize/deserialize your first object. +* [Extend to your needs](first_extension.md) by enabling serialization/deserialization depending on version number. * `Squeeze Me!` compress your data when you know what it stores. * `Anything is Possible` extend library for custom container, compress geometry and more. * `Little or Big` change endianness if you want best performance on PowerPC. diff --git a/doc/tutorial/composition.md b/doc/tutorial/composition.md deleted file mode 100644 index aed8999..0000000 --- a/doc/tutorial/composition.md +++ /dev/null @@ -1,3 +0,0 @@ -*document in progress* -* explain why *value* and *object* is fundamental functions. -* write about *Growable* extension \ No newline at end of file diff --git a/doc/tutorial/first_extension.md b/doc/tutorial/first_extension.md new file mode 100644 index 0000000..ec02851 --- /dev/null +++ b/doc/tutorial/first_extension.md @@ -0,0 +1,67 @@ +... TODO explain step-by-step what we need and how to get there + +Instead I immediately provide implementation for an extension. + +```cpp +#include "../details/adapter_common.h" +#include "../traits/core/traits.h" + +namespace bitsery { + + namespace ext { + + template + class Version { + public: + + template + void serialize(Ser &ser, const T &v, Fnc &&fnc) const { + details::writeSize(ser.adapter(), VERSION); + fnc(ser, const_cast(v), VERSION); + } + + template + void deserialize(Des &des, T &v, Fnc &&fnc) const { + size_t version{}; + details::readSize(des.adapter(), version, 0u, std::false_type{}); + fnc(des, v, version); + } + + }; + } + + namespace traits { + template + struct ExtensionTraits, T> { + using TValue = T; + static constexpr bool SupportValueOverload = false; + static constexpr bool SupportObjectOverload = false; + static constexpr bool SupportLambdaOverload = true; + }; + } + +} +``` +Adding such extension to the bitsery itself is impractical because it is very easy to implement, but at the same time it has a lot of customization options that actual user might require e.g.: +* how do you want to handle reading/writing version number? (in this case use compact representation as size, but do not check for errors if version number is too large) +* maybe you want to be able to set ReaderError, when version is larger than deserialization implementation handles. (we simply ignore this case and later we'll probably get reading error later anyway) +* or maybe you want to wrap object in `Growable` extension? so that you could ignore unknown fields in newer version of object. + +Example of how to use this provided implementation: +```cpp + +struct TypeV2 { + uint16_t x{}; + uint16_t y{}; +}; + +template +void serialize(S& ser, TypeV2& obj) { + ser.ext(obj, bitsery::ext::Version<2u>{}, [](S& s, TypeV2&o, size_t version) { + s.value2b(o.x); + if (version == 2u) { + s.value2b(o.y); + } + }); +} +``` \ No newline at end of file diff --git a/doc/tutorial/hello_world.md b/doc/tutorial/hello_world.md index 8e3cedc..5684202 100644 --- a/doc/tutorial/hello_world.md +++ b/doc/tutorial/hello_world.md @@ -18,11 +18,9 @@ There's nothing to build or make - **bitsery** is header only. #include #include -using namespace bitsery; - using Buffer = std::vector; -using OutputAdapter = OutputBufferAdapter; -using InputAdapter = InputBufferAdapter; +using OutputAdapter = bitsery::OutputBufferAdapter; +using InputAdapter = bitsery::InputBufferAdapter; ``` @@ -62,7 +60,7 @@ void serialize(S& s, MyStruct& o) { This example we choosed probably unfamiliar verbose syntax, so lets explain core functionality that you'll use all the time: * **s.value4b(o.i);** serialize fundamental types (ints, floats, enums) value**4b** means, that data type is 4 bytes. If you use same code on different machines, if it compiles it means it is compatible. -* **s.text1b(o.str);** serialize text (null-terminated) of char type, if you use *wchar* then you would write *text2b*. +* **s.text1b(o.str);** serialize text (null-terminated) of char type, if you use *wchar* then you would write *text2b* or *text4b* depending on the OS platform. * **s.container4b(o.fs, 100);** serializes any container of fundamental types of size 4bytes, **100** is max size of container. **Bitsery** is designed to be save with untrusted (malicious) data from network, so for dynamic containers you always need to provide max possible size available, to avoid buffer-overflow attacks. **text** didn't had this max size specified, because it was serializing fixed size container. @@ -76,8 +74,8 @@ Create buffer and use helper functions for serialization and deserialization. ```cpp Buffer buffer; - auto writtenSize = quickSerialization(OutputAdapter{buffer}, data); - auto state = quickDeserialization(InputAdapter{buffer.begin(), writtenSize}, res); + auto writtenSize = bitsery::quickSerialization(OutputAdapter{buffer}, data); + auto state = bitsery::quickDeserialization(InputAdapter{buffer.begin(), writtenSize}, res); ``` These helper functions use default configuration *bitsery::DefaultConfig* @@ -93,11 +91,9 @@ deserialization state has two properties, error code and bool that indicates if #include #include -using namespace bitsery; - using Buffer = std::vector; -using OutputAdapter = OutputBufferAdapter; -using InputAdapter = InputBufferAdapter; +using OutputAdapter = bitsery::OutputBufferAdapter; +using InputAdapter = bitsery::InputBufferAdapter; struct MyStruct { uint32_t i; @@ -110,17 +106,17 @@ void serialize(S& s, MyStruct& o) { s.value4b(o.i); s.text1b(o.str); s.container4b(o.fs, 100); -}; +} int main() { MyStruct data{8941, "hello", {15.0f, -8.5f, 0.045f}}; MyStruct res{}; Buffer buffer; - auto writtenSize = quickSerialization(OutputAdapter{buffer}, data); - auto state = quickDeserialization(InputAdapter{buffer.begin(), writtenSize}, res); + auto writtenSize = bitsery::quickSerialization(OutputAdapter{buffer}, data); + auto state = bitsery::quickDeserialization(InputAdapter{buffer.begin(), writtenSize}, res); - assert(state.first == ReaderError::NoError && state.second); + assert(state.first == bitsery::ReaderError::NoError && state.second); assert(data.fs == res.fs && data.i == res.i && std::strcmp(data.str, res.str) == 0); } ``` diff --git a/doc/tutorial/two_in_one.md b/doc/tutorial/two_in_one.md deleted file mode 100644 index e69de29..0000000 diff --git a/examples/basic_usage.cpp b/examples/basic_usage.cpp index 2d91928..b85134b 100644 --- a/examples/basic_usage.cpp +++ b/examples/basic_usage.cpp @@ -22,12 +22,10 @@ void serialize(S& s, MyStruct& o) { s.container4b(o.fs, 10);//resizable containers also requires maxSize, to make it safe from buffer-overflow attacks } -using namespace bitsery; - //some helper types using Buffer = std::vector; -using OutputAdapter = OutputBufferAdapter; -using InputAdapter = InputBufferAdapter; +using OutputAdapter = bitsery::OutputBufferAdapter; +using InputAdapter = bitsery::InputBufferAdapter; int main() { //set some random data @@ -39,12 +37,12 @@ int main() { //use quick serialization function, //it will use default configuration to setup all the nesessary steps //and serialize data to container - auto writtenSize = quickSerialization(buffer, data); + auto writtenSize = bitsery::quickSerialization(buffer, data); //same as serialization, but returns deserialization state as a pair //first = error code, second = is buffer was successfully read from begin to the end. - auto state = quickDeserialization({buffer.begin(), writtenSize}, res); + auto state = bitsery::quickDeserialization({buffer.begin(), writtenSize}, res); - assert(state.first == ReaderError::NoError && state.second); + assert(state.first == bitsery::ReaderError::NoError && state.second); assert(data.fs == res.fs && data.i == res.i && data.e == res.e); } diff --git a/examples/bit_packing.cpp b/examples/bit_packing.cpp index 8ac58a9..fb8cee8 100644 --- a/examples/bit_packing.cpp +++ b/examples/bit_packing.cpp @@ -41,12 +41,10 @@ namespace MyTypes { } } -using namespace bitsery; - //use fixed-size buffer using Buffer = std::array; -using OutputAdapter = OutputBufferAdapter; -using InputAdapter = InputBufferAdapter; +using OutputAdapter = bitsery::OutputBufferAdapter; +using InputAdapter = bitsery::InputBufferAdapter; int main() { //set some random data @@ -55,10 +53,10 @@ int main() { //create buffer to store data to Buffer buffer{}; - auto writtenSize = quickSerialization(buffer, data); + auto writtenSize = bitsery::quickSerialization(buffer, data); MyTypes::Monster res{}; - auto state = quickDeserialization({buffer.begin(), writtenSize}, res); + auto state = bitsery::quickDeserialization({buffer.begin(), writtenSize}, res); - assert(state.first == ReaderError::NoError && state.second); + assert(state.first == bitsery::ReaderError::NoError && state.second); } diff --git a/examples/brief_syntax.cpp b/examples/brief_syntax.cpp index 3988d2e..49e42c0 100644 --- a/examples/brief_syntax.cpp +++ b/examples/brief_syntax.cpp @@ -23,12 +23,10 @@ struct MyStruct { }; -using namespace bitsery; - //some helper types using Buffer = std::vector; -using OutputAdapter = OutputBufferAdapter; -using InputAdapter = InputBufferAdapter; +using OutputAdapter = bitsery::OutputBufferAdapter; +using InputAdapter = bitsery::InputBufferAdapter; int main() { //set some random data @@ -37,10 +35,10 @@ int main() { //serialization, deserialization flow is unchanged as in basic usage Buffer buffer; - auto writtenSize = quickSerialization(buffer, data); + auto writtenSize = bitsery::quickSerialization(buffer, data); - auto state = quickDeserialization({buffer.begin(), writtenSize}, res); + auto state = bitsery::quickDeserialization({buffer.begin(), writtenSize}, res); - assert(state.first == ReaderError::NoError && state.second); + assert(state.first == bitsery::ReaderError::NoError && state.second); assert(data.fs == res.fs && data.i == res.i && data.e == res.e); } diff --git a/examples/composite_types.cpp b/examples/composite_types.cpp index f16fa19..399ebb5 100644 --- a/examples/composite_types.cpp +++ b/examples/composite_types.cpp @@ -29,27 +29,24 @@ void serialize(S& s, MyStruct& o) { using MyTuple = std::tuple; using MyVariant = std::variant; -// for convenience -using namespace bitsery; - // define default serialize function for MyVariant, so that we could use quickSerialization/Deserialization functions template void serialize(S& s, MyVariant& o) { // in order to serialize a variant, it needs to know how to do it for all types // we can do this simply by providing any callable object, that accepts serializer and type as arguments - s.ext(o, ext::StdVariant{ + s.ext(o, bitsery::ext::StdVariant{ // specify how to serialize tuple by creating a lambda [](S& s, MyTuple& o) { // StdTuple is used exactly the same as StdVariant - s.ext(o, ext::StdTuple{ + s.ext(o, bitsery::ext::StdTuple{ // this is convenient callable object to specify integral value size // it is different equivalent to lambda [](auto& s, float&o) { s.value4b(o);} - ext::OverloadValue{}, + bitsery::ext::OverloadValue{}, // it is not required to provide MyStruct overload, because it we have defined 'serialize' function for it }); }, // this might also be useful if you want to overload using extension - ext::OverloadExtValue{}, + bitsery::ext::OverloadExtValue{}, // you can even go further and instead of writing lambda for MyTuple you can as well compose the same functionality // with OverloadExtObject, like this: // (comment out MyTuple lambda, and uncomment this) @@ -59,7 +56,7 @@ void serialize(S& s, MyVariant& o) { [](S& s, MyStruct& o) { s.value4b(o.f); s.container(o.v, 1000, [](S& s, int32_t& v) { - s.ext4b(v, ext::CompactValue{}); + s.ext4b(v, bitsery::ext::CompactValue{}); }); }, // NOTE. @@ -78,8 +75,8 @@ void serialize(S& s, MyVariant& o) { //some helper types using Buffer = std::vector; -using OutputAdapter = OutputBufferAdapter; -using InputAdapter = InputBufferAdapter; +using OutputAdapter = bitsery::OutputBufferAdapter; +using InputAdapter = bitsery::InputBufferAdapter; int main() { @@ -93,13 +90,13 @@ int main() { //use quick serialization function, //it will use default configuration to setup all the nesessary steps //and serialize data to container - auto writtenSize = quickSerialization(buffer, data); + auto writtenSize = bitsery::quickSerialization(buffer, data); //same as serialization, but returns deserialization state as a pair //first = error code, second = is buffer was successfully read from begin to the end. - auto state = quickDeserialization({buffer.begin(), writtenSize}, res); + auto state = bitsery::quickDeserialization({buffer.begin(), writtenSize}, res); - assert(state.first == ReaderError::NoError && state.second); + assert(state.first == bitsery::ReaderError::NoError && state.second); assert(data == res); } #else diff --git a/examples/context_usage.cpp b/examples/context_usage.cpp index 39a33ed..0f0bb19 100644 --- a/examples/context_usage.cpp +++ b/examples/context_usage.cpp @@ -67,10 +67,9 @@ using Context = std::tuple>; //use fixed-size buffer using Buffer = std::vector; -using namespace bitsery; // define adapter types, -using OutputAdapter = OutputBufferAdapter; -using InputAdapter = InputBufferAdapter; +using OutputAdapter = bitsery::OutputBufferAdapter; +using InputAdapter = bitsery::InputBufferAdapter; int main() { @@ -90,10 +89,10 @@ int main() { //create buffer to store data to Buffer buffer{}; - auto writtenSize = quickSerialization(ctx, OutputAdapter{buffer}, data); + auto writtenSize = bitsery::quickSerialization(ctx, OutputAdapter{buffer}, data); MyTypes::GameState res{}; - auto state = quickDeserialization(ctx, InputAdapter{buffer.begin(), writtenSize}, res); + auto state = bitsery::quickDeserialization(ctx, InputAdapter{buffer.begin(), writtenSize}, res); - assert(state.first == ReaderError::NoError && state.second); + assert(state.first == bitsery::ReaderError::NoError && state.second); } diff --git a/examples/file_stream.cpp b/examples/file_stream.cpp index b36a53e..8016690 100644 --- a/examples/file_stream.cpp +++ b/examples/file_stream.cpp @@ -19,8 +19,6 @@ void serialize(S& s, MyStruct& o) { s.value8b(o.f); } -using namespace bitsery; - int main() { //set some random data MyStruct data{8941, MyEnum::V2, 0.045}; @@ -35,7 +33,7 @@ int main() { } //we cannot use quick serialization function, because streams cannot use writtenBytesCount method - Serializer ser{s}; + bitsery::Serializer ser{s}; ser.object(data); //flush to writer ser.adapter().flush(); @@ -50,8 +48,8 @@ int main() { //same as serialization, but returns deserialization state as a pair //first = error code, second = is buffer was successfully read from begin to the end. - auto state = quickDeserialization(s, res); + auto state = bitsery::quickDeserialization(s, res); - assert(state.first == ReaderError::NoError && state.second); + assert(state.first == bitsery::ReaderError::NoError && state.second); assert(data.f == res.f && data.i == res.i && data.e == res.e); } diff --git a/examples/forward_backward_compatibility.cpp b/examples/forward_backward_compatibility.cpp index a94af2b..4ce2161 100644 --- a/examples/forward_backward_compatibility.cpp +++ b/examples/forward_backward_compatibility.cpp @@ -68,12 +68,10 @@ namespace MyTypes { } } -using namespace bitsery; - //use fixed-size buffer using Buffer = std::array; -using OutputAdapter = OutputBufferAdapter; -using InputAdapter = InputBufferAdapter; +using OutputAdapter = bitsery::OutputBufferAdapter; +using InputAdapter = bitsery::InputBufferAdapter; int main() { //set some random data @@ -84,11 +82,11 @@ int main() { //create buffer to store data to Buffer buffer{}; //since we're using different configuration, we cannot use quickSerialization function. - auto writtenSize = quickSerialization(buffer, data); + auto writtenSize = bitsery::quickSerialization(buffer, data); MyTypes::Monster res{}; //deserialize - auto state = quickDeserialization({buffer.begin(), writtenSize}, res); + auto state = bitsery::quickDeserialization({buffer.begin(), writtenSize}, res); - assert(state.first == ReaderError::NoError && state.second); + assert(state.first == bitsery::ReaderError::NoError && state.second); } diff --git a/examples/inheritance.cpp b/examples/inheritance.cpp index 1d3c27e..8d46b2f 100644 --- a/examples/inheritance.cpp +++ b/examples/inheritance.cpp @@ -78,13 +78,10 @@ namespace bitsery { struct SelectSerializeFnc:UseNonMemberFnc {}; } -using namespace bitsery; - - //some helper types using Buffer = std::vector; -using Writer = OutputBufferAdapter; -using Reader = InputBufferAdapter; +using Writer = bitsery::OutputBufferAdapter; +using Reader = bitsery::InputBufferAdapter; int main() { @@ -95,13 +92,13 @@ int main() { Buffer buf{}; - ext::InheritanceContext ctx1; - auto writtenSize = quickSerialization(ctx1, Writer{buf}, data); + bitsery::ext::InheritanceContext ctx1; + auto writtenSize = bitsery::quickSerialization(ctx1, Writer{buf}, data); assert(writtenSize == 4);//base is serialized once, because it is inherited virtually MultipleInheritance res{0}; - ext::InheritanceContext ctx2; - auto state = quickDeserialization(ctx2, Reader{buf.begin(), writtenSize}, res); - assert(state.first == ReaderError::NoError && state.second); + bitsery::ext::InheritanceContext ctx2; + auto state = bitsery::quickDeserialization(ctx2, Reader{buf.begin(), writtenSize}, res); + assert(state.first == bitsery::ReaderError::NoError && state.second); assert(data.x == res.x && data.y1 == res.y1 && data.getY2() == res.getY2() && data.z == res.z); } diff --git a/examples/non_default_constructible.cpp b/examples/non_default_constructible.cpp index 94f48b7..f9379bf 100644 --- a/examples/non_default_constructible.cpp +++ b/examples/non_default_constructible.cpp @@ -30,12 +30,10 @@ public: } }; -using namespace bitsery; - //some helper types using Buffer = std::vector; -using Writer = OutputBufferAdapter; -using Reader = InputBufferAdapter; +using Writer = bitsery::OutputBufferAdapter; +using Reader = bitsery::InputBufferAdapter; int main() { @@ -49,16 +47,16 @@ int main() { //we cant use quick (de)serialization helper methods, because we ant to serialize container directly //create writer and serialize container - Serializer ser{buffer}; + bitsery::Serializer ser{buffer}; ser.container(data, 10); ser.adapter().flush(); //create reader and deserialize container - Deserializer des{buffer.begin(), ser.adapter().writtenBytesCount()}; + bitsery::Deserializer des{buffer.begin(), ser.adapter().writtenBytesCount()}; des.container(res, 10); //check if everything went ok - assert(des.adapter().error() == ReaderError::NoError && des.adapter().isCompletedSuccessfully()); + assert(des.adapter().error() == bitsery::ReaderError::NoError && des.adapter().isCompletedSuccessfully()); assert(res == data); } diff --git a/examples/raw_pointers.cpp b/examples/raw_pointers.cpp index 1f6435d..0151ad3 100644 --- a/examples/raw_pointers.cpp +++ b/examples/raw_pointers.cpp @@ -78,12 +78,10 @@ private: } }; -using namespace bitsery; - //some helper types using Buffer = std::vector; -using Writer = OutputBufferAdapter; -using Reader = InputBufferAdapter; +using Writer = bitsery::OutputBufferAdapter; +using Reader = bitsery::InputBufferAdapter; //we will need PointerLinkingContext to work with pointers //if we would require additional context for our own custom flow, we can define it as tuple like this: @@ -114,7 +112,7 @@ int main() { size_t writtenSize{}; //in order to use pointers, we need to pass pointer linking context serializer/deserializer { - ext::PointerLinkingContext ctx{}; + bitsery::ext::PointerLinkingContext ctx{}; writtenSize = quickSerialization(ctx, Writer{buffer}, data); //make sure that pointer linking context is valid @@ -125,10 +123,10 @@ int main() { Test1Data res{}; { - ext::PointerLinkingContext ctx{}; + bitsery::ext::PointerLinkingContext ctx{}; auto state = quickDeserialization(ctx, Reader{buffer.begin(), writtenSize}, res); //check if everything went find - assert(state.first == ReaderError::NoError && state.second); + assert(state.first == bitsery::ReaderError::NoError && state.second); //also check for dangling pointers, after deserialization assert(ctx.isValid()); } diff --git a/examples/smart_pointers_with_polymorphism.cpp b/examples/smart_pointers_with_polymorphism.cpp index e0f8751..db30249 100644 --- a/examples/smart_pointers_with_polymorphism.cpp +++ b/examples/smart_pointers_with_polymorphism.cpp @@ -181,23 +181,21 @@ namespace bitsery { // also it automatically ensures, that classes is registered in the same order for serialization and deserialization using MyPolymorphicClassesForRegistering = bitsery::ext::PolymorphicClassesList; - -//use bitsery namespace for convenience -using namespace bitsery; - //some helper types using Buffer = std::vector; -using Writer = OutputBufferAdapter; -using Reader = InputBufferAdapter; +using Writer = bitsery::OutputBufferAdapter; +using Reader = bitsery::InputBufferAdapter; //we need to define few things in order to work with polymorphism //1) we need pointer linking context to work with pointers //2) we need polymorphic context to be able to work with polymorphic types -using TContext = std::tuple>; +using TContext = std::tuple< + bitsery::ext::PointerLinkingContext, + bitsery::ext::PolymorphicContext>; //NOTE: // RTTI can be customizable, if you can't use dynamic_cast and typeid, and have 'custom' solution -using MySerializer = Serializer; -using MyDeserializer = Deserializer; +using MySerializer = bitsery::Serializer; +using MyDeserializer = bitsery::Deserializer; //checks if deserialized data is equal void assertSameShapes(const SomeShapes &data, const SomeShapes &res) { @@ -257,7 +255,7 @@ int main() { //deserialize our data MyDeserializer des{ctx, buffer.begin(), writtenSize}; des.object(res); - assert(des.adapter().error() == ReaderError::NoError && des.adapter().isCompletedSuccessfully()); + assert(des.adapter().error() == bitsery::ReaderError::NoError && des.adapter().isCompletedSuccessfully()); //also check for dangling pointers, after deserialization assert(std::get<0>(ctx).isValid()); // clear shared state from pointer linking context,