added extension support, and changed invoke parameters for custom serialization function

This commit is contained in:
fraillt
2017-06-09 11:41:56 +03:00
parent 1176f4908e
commit 014b072b96
16 changed files with 259 additions and 99 deletions

View File

@@ -35,9 +35,9 @@ struct MyStruct {
//define how object should be serialized/deserialized
SERIALIZE(MyStruct) {
return s.
value(o.i).
value(o.e).
container(o.fs, 100);
value4(o.i).
value4(o.e).
container4(o.fs, 100);
}
using namespace bitsery;

View File

@@ -36,24 +36,24 @@ namespace bitsery {
using value_type = uint8_t;
BufferReader(const std::vector<uint8_t> &buf)
: _pos{buf.data()},
_end{buf.data() + buf.size()} {
BufferReader(const std::vector<uint8_t> &buf) : _pos{buf.data()}, _end{buf.data() + buf.size()} {
}
BufferReader(const uint8_t* data, size_t size)
: _pos{data},
_end{data + size}
BufferReader(const uint8_t* data, size_t size) : _pos{data}, _end{data + size}
{
}
template <size_t N>
BufferReader(const uint8_t (&data)[N])
: _pos{data},
_end{data + N}
BufferReader(const uint8_t (&data)[N]): _pos{data}, _end{data + N}
{
}
BufferReader(const BufferReader&) = delete;
BufferReader& operator=(const BufferReader& ) = delete;
BufferReader(BufferReader&&) noexcept = default;
BufferReader& operator=(BufferReader&&) noexcept = default;
~BufferReader() noexcept = default;
template<size_t SIZE, typename T>
bool readBytes(T &v) {

View File

@@ -69,10 +69,16 @@ namespace bitsery {
struct BufferWriter {
using value_type = uint8_t;
BufferWriter(std::vector<uint8_t> &buffer) : _buf{buffer}, _outIt{std::back_inserter(buffer)} {
explicit BufferWriter(std::vector<uint8_t> &buffer) : _buf{buffer}, _outIt{std::back_inserter(buffer)} {
static_assert(std::is_unsigned<value_type>::value, "");
}
BufferWriter(const BufferWriter&) = delete;
BufferWriter& operator=(const BufferWriter& ) = delete;
BufferWriter(BufferWriter&&) noexcept = default;
BufferWriter& operator=(BufferWriter&&) noexcept = default;
~BufferWriter() noexcept = default;
template<size_t SIZE, typename T>
void writeBytes(const T &v) {
static_assert(std::is_integral<T>(), "");

View File

@@ -71,9 +71,6 @@ namespace bitsery {
typedef int16_t type;
};
template<typename T>
constexpr size_t ARITHMETIC_OR_ENUM_SIZE = std::is_arithmetic<T>::value || std::is_enum<T>::value ? sizeof(T) : 0;
template<typename T, typename Enable = void>
struct SAME_SIZE_UNSIGNED_TYPE {

View File

@@ -85,7 +85,7 @@ namespace bitsery {
processContainer(std::begin(old), std::end(old), std::begin(arr), std::end(arr), fnc);
} else {
for (auto &v:arr)
fnc(v);
fnc(*this, v);
}
}
return *this;
@@ -102,14 +102,14 @@ namespace bitsery {
} else {
T *tmp = arr;
for (auto i = 0u; i < N; ++i, ++tmp)
fnc(*tmp);
fnc(*this, *tmp);
}
}
return *this;
}
template<typename T, typename Fnc>
DeltaDeserializer &container(T &obj, Fnc &&fnc, size_t maxSize) {
DeltaDeserializer &container(T &obj, size_t maxSize, Fnc &&fnc) {
if (getChangedState(obj)) {
size_t newSize{};
_reader.readBits(newSize, 32);
@@ -122,7 +122,7 @@ namespace bitsery {
} else {
obj.resize(newSize);
for (auto &v:obj)
fnc(v);
fnc(*this, v);
}
}
return *this;
@@ -174,7 +174,7 @@ namespace bitsery {
--offset;
} else {
_objMemPos.emplace(ObjectMemoryPosition{*pOld, *p});
fnc(*p);
fnc(*this, *p);
_objMemPos.pop();
offset = readIndexOffset();
}
@@ -183,7 +183,7 @@ namespace bitsery {
return false;
_isNewElement = true;
for (; p != end; ++p, --offset)
fnc(*p);
fnc(*this, *p);
_isNewElement = false;
return offset == 0;

View File

@@ -88,7 +88,7 @@ namespace bitsery {
processContainer(std::begin(old), std::end(old), std::begin(arr), std::end(arr), fnc);
} else {
for (auto &v:arr)
fnc(v);
fnc(*this, v);
}
}
return *this;
@@ -105,14 +105,14 @@ namespace bitsery {
} else {
const T *tmp = arr;
for (auto i = 0u; i < N; ++i, ++tmp)
fnc(*tmp);
fnc(*this, *tmp);
}
}
return *this;
}
template<typename T, typename Fnc>
DeltaSerializer &container(T &&obj, Fnc &&fnc, size_t maxSize) {
DeltaSerializer &container(T &&obj, size_t maxSize, Fnc &&fnc) {
if (setChangedState(obj)) {
_writter.writeBits(obj.size(), 32);
if (!_isNewElement) {
@@ -121,7 +121,7 @@ namespace bitsery {
std::forward<Fnc>(fnc));
} else {
for (auto &v:obj)
fnc(v);
fnc(*this, v);
}
}
return *this;
@@ -171,7 +171,7 @@ namespace bitsery {
while (misMatch.first != oldEnd && misMatch.second != end) {
writeIndexOffset(std::distance(lastChanged, misMatch.second));
_objMemPos.emplace(ObjectMemoryPosition{*misMatch.first, *misMatch.second});
fnc(*misMatch.second);
fnc(*this, *misMatch.second);
_objMemPos.pop();
++misMatch.first;
++misMatch.second;
@@ -184,14 +184,14 @@ namespace bitsery {
//write old elements
for (auto pOld = misMatch.first; p != end && pOld != oldEnd; ++p, ++pOld) {
_objMemPos.emplace(ObjectMemoryPosition{*pOld, *p});
fnc(*p);
fnc(*this, *p);
_objMemPos.pop();
}
//write new elements
_isNewElement = true;
for (; p != end; ++p)
fnc(*p);
fnc(*this, *p);
_isNewElement = false;
}

View File

@@ -63,6 +63,14 @@ namespace bitsery {
return serialize(*this, std::forward<T>(obj));
}
template <template <typename> class Extension, typename TValue, typename Fnc>
Deserializer& ext(TValue& v, Fnc&& fnc) {
static_assert(!std::is_const<TValue>(), "");
Extension<TValue> ext{v};
ext.deserialize(*this, std::forward<Fnc>(fnc));
return *this;
};
/*
* value overloads
*/
@@ -143,7 +151,7 @@ namespace bitsery {
if (index)
v = expectedValues[index-1];
else
fnc(v);
fnc(*this, v);
}
return *this;
};
@@ -213,14 +221,14 @@ namespace bitsery {
*/
template <typename T, typename Fnc>
Deserializer& container(T&& obj, Fnc&& fnc, size_t maxSize) {
Deserializer& container(T&& obj, size_t maxSize, Fnc&& fnc) {
decltype(obj.size()) size{};
readSize(size, maxSize);
if (_isValid) {
obj.resize(size);
for (auto& v:obj) {
if (_isValid)
fnc(v);
fnc(*this, v);
}
}
@@ -265,7 +273,7 @@ namespace bitsery {
Deserializer& array(std::array<T,N> &arr, Fnc && fnc) {
for (auto& v: arr)
if (_isValid)
fnc(v);
fnc(*this, v);
return *this;
}
@@ -294,7 +302,7 @@ namespace bitsery {
T* end = arr + N;
for (T* it= arr; it != end; ++it) {
if (_isValid)
fnc(*it);
fnc(*this, *it);
}
return *this;
}
@@ -307,7 +315,7 @@ namespace bitsery {
template<typename T, size_t N>
Deserializer& array(T (&arr)[N]) {
procCArray<ARITHMETIC_OR_ENUM_SIZE<T>>(arr);
procCArray<0>(arr);
return *this;
}
bool isValid() const {

View File

@@ -0,0 +1,67 @@
//MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
#ifndef BITSERY_EXT_OPTIONAL_H
#define BITSERY_EXT_OPTIONAL_H
namespace bitsery {
namespace ext {
template <typename T>
using std_optional = ::std::optional<T>;
template <typename T>
class optional {
public:
explicit optional(T& v):_value{v} {
using TOpt = typename std::remove_cv<T>::type;
using TVal = typename TOpt::value_type;
static_assert(std::is_same<TOpt, std_optional<TVal>>(), "");
};
template <typename TSerializer, typename Fnc>
void serialize(TSerializer& ser, const Fnc& fnc) {
ser.boolByte(static_cast<bool>(_value));
if (_value)
fnc(ser, *_value);
}
template <typename TSerializer, typename Fnc>
void deserialize(TSerializer& ser, const Fnc& fnc) {
bool exists{};
ser.boolByte(exists);
if (exists) {
typename T::value_type tmp{};
fnc(ser, tmp);
_value = tmp;
} else {
_value = T{};
}
}
private:
T& _value;
};
}
}
#endif //BITSERY_EXT_OPTIONAL_H

View File

@@ -80,6 +80,14 @@ namespace bitsery {
return serialize(*this, obj);
}
template <template <typename> class Extension, typename TValue, typename Fnc>
Serializer& ext(const TValue& v, Fnc&& fnc ) {
Extension<const TValue> ext{v};
ext.serialize(*this, std::forward<Fnc>(fnc));
return *this;
};
/*
* value overloads
*/
@@ -136,7 +144,7 @@ namespace bitsery {
auto index = findSubstitutionIndex(v, expectedValues);
range(index, {{}, N +1});
if (!index)
fnc(v);
fnc(*this, v);
return *this;
};
@@ -180,16 +188,17 @@ namespace bitsery {
*/
template<typename T, typename Fnc>
Serializer& container(const T &obj, Fnc &&fnc, size_t maxSize) {
Serializer& container(const T &obj, size_t maxSize, Fnc &&fnc) {
assert(obj.size() <= maxSize);
writeSize(obj.size());
for (auto &v: obj)
fnc(v);
fnc(*this, v);
return *this;
}
template<size_t VSIZE, typename T>
Serializer& container(const T &obj, size_t maxSize) {
static_assert(VSIZE > 0, "");
assert(obj.size() <= maxSize);
writeSize(obj.size());
procContainer<VSIZE>(obj);
@@ -200,7 +209,7 @@ namespace bitsery {
Serializer& container(const T &obj, size_t maxSize) {
assert(obj.size() <= maxSize);
writeSize(obj.size());
procContainer<ARITHMETIC_OR_ENUM_SIZE<typename T::value_type>>(obj);
procContainer<0>(obj);
return *this;
}
@@ -213,19 +222,20 @@ namespace bitsery {
template<typename T, size_t N, typename Fnc>
Serializer& array(const std::array<T, N> &arr, Fnc &&fnc) {
for (auto &v: arr)
fnc(v);
fnc(*this, v);
return *this;
}
template<size_t VSIZE, typename T, size_t N>
Serializer& array(const std::array<T, N> &arr) {
static_assert(VSIZE > 0, "");
procContainer<VSIZE>(arr);
return *this;
}
template<typename T, size_t N>
Serializer& array(const std::array<T, N> &arr) {
procContainer<ARITHMETIC_OR_ENUM_SIZE<T>>(arr);
procContainer<0>(arr);
return *this;
}
@@ -235,19 +245,20 @@ namespace bitsery {
Serializer& array(const T (&arr)[N], Fnc &&fnc) {
const T *end = arr + N;
for (const T *tmp = arr; tmp != end; ++tmp)
fnc(*tmp);
fnc(*this, *tmp);
return *this;
}
template<size_t VSIZE, typename T, size_t N>
Serializer& array(const T (&arr)[N]) {
static_assert(VSIZE > 0, "");
procCArray<VSIZE>(arr);
return *this;
}
template<typename T, size_t N>
Serializer& array(const T (&arr)[N]) {
procCArray<ARITHMETIC_OR_ENUM_SIZE<T>>(arr);
procCArray<0>(arr);
return *this;
}
@@ -291,6 +302,16 @@ namespace bitsery {
template<typename T> Serializer& container8(T &&obj, size_t maxSize) {
return container<8>(std::forward<T>(obj), maxSize); }
template<typename T, size_t N> Serializer& array1(const std::array<T, N> &arr) { return array<1>(arr); }
template<typename T, size_t N> Serializer& array2(const std::array<T, N> &arr) { return array<2>(arr); }
template<typename T, size_t N> Serializer& array4(const std::array<T, N> &arr) { return array<4>(arr); }
template<typename T, size_t N> Serializer& array8(const std::array<T, N> &arr) { return array<8>(arr); }
template<typename T, size_t N> Serializer& array1(const T (&arr)[N]) { return array<1>(arr); }
template<typename T, size_t N> Serializer& array2(const T (&arr)[N]) { return array<2>(arr); }
template<typename T, size_t N> Serializer& array4(const T (&arr)[N]) { return array<4>(arr); }
template<typename T, size_t N> Serializer& array8(const T (&arr)[N]) { return array<8>(arr); }
private:
Writter &_writter;

View File

@@ -72,17 +72,17 @@ TYPED_TEST(SerializeContainerArthmeticTypes, CustomFunctionIncrements) {
SerializationContext ctx{};
auto ser = ctx.createSerializer();
ser.container(this->src, [&ser](auto v ) {
ser.container(this->src, 1000, [](auto &s, auto v) {
//increment by 1 before writing
v++;
ser.value<sizeof(v)>(v);
}, 1000);
s.template value<sizeof(v)>(v);
});
auto des = ctx.createDeserializer();
des.container(this->res, [&des](auto&v ) {
des.value<sizeof(v)>(v);
des.container(this->res, 1000, [](auto &s, auto&v ) {
s.template value<sizeof(v)>(v);
//increment by 1 after reading
v++;
}, 1000);
});
//decrement result by 2, before comparing for eq
for(auto& v:this->res)
v -= 2;
@@ -149,9 +149,9 @@ TYPED_TEST(SerializeContainerCompositeTypes, CustomFunctionThatDoNothing) {
SerializationContext ctx{};
auto emptyFnc = [](auto v) {};
ctx.createSerializer().container(this->src, emptyFnc, 1000);
ctx.createDeserializer().container(this->res, emptyFnc, 1000);
auto emptyFnc = [](auto& s, auto& v) {};
ctx.createSerializer().container(this->src, 1000, emptyFnc);
ctx.createDeserializer().container(this->res, 1000, emptyFnc);
EXPECT_THAT(ctx.getBufferSize(), Eq(ctx.containerSizeSerializedBytesCount(this->src.size())));
}

View File

@@ -0,0 +1,85 @@
//MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <experimental/optional>
namespace std {
template <typename T>
using optional = experimental::optional<T>;
};
#include <bitsery/ext/optional.h>
template <typename T>
using extoptional = bitsery::ext::optional<T>;
using testing::Eq;
template <typename T>
void test(SerializationContext& ctx, const T& v, T& r) {
auto fnc = [](auto ser, auto& v) {
ser.template value<sizeof(v)>(v);
};
ctx.createSerializer().ext<extoptional>(v, fnc);
ctx.createDeserializer().ext<extoptional>(r, fnc);
}
TEST(SerializeExtensionOptional, EmptyOptional) {
std::optional<int> t1{};
std::optional<int> r1{};
SerializationContext ctx1;
test(ctx1,t1, r1);
EXPECT_THAT(ctx1.getBufferSize(), Eq(1));
EXPECT_THAT(t1, Eq(r1));
r1 = 3;
SerializationContext ctx2;
test(ctx2,t1, r1);
EXPECT_THAT(ctx2.getBufferSize(), Eq(1));
EXPECT_THAT(t1, Eq(r1));
}
TEST(SerializeExtensionOptional, OptionalHasValue) {
std::optional<int> t1{43};
std::optional<int> r1{52};
SerializationContext ctx1;
test(ctx1,t1, r1);
EXPECT_THAT(ctx1.getBufferSize(), Eq(1 + sizeof(int)));
EXPECT_THAT(t1.value(), Eq(r1.value()));
r1 = std::optional<int>{};
SerializationContext ctx2;
test(ctx2,t1, r1);
EXPECT_THAT(ctx2.getBufferSize(), Eq(1 + sizeof(int)));
EXPECT_THAT(t1.value(), Eq(r1.value()));
}

View File

@@ -41,19 +41,6 @@ TEST(SerializeFSArrayStdArray, ArithmeticValues) {
}
TEST(SerializeFSArrayStdArray, ArithmeticValuesSettingValueSizeExplicitly) {
SerializationContext ctx;
std::array<int, 4> src{5,9,15,-459};
std::array<int, 4> res{};
ctx.createSerializer().array<sizeof(int)>(src);
ctx.createDeserializer().array<sizeof(int)>(res);
EXPECT_THAT(ctx.getBufferSize(), Eq(src.size() * sizeof(int)));
EXPECT_THAT(res, ContainerEq(src));
}
TEST(SerializeFSArrayStdArray, CompositeTypes) {
SerializationContext ctx;
std::array<MyStruct1, 7> src{
@@ -78,34 +65,20 @@ TEST(SerializeFSArrayStdArray, CustomFunctionThatSerializesAnEmptyByteEveryEleme
auto ser = ctx.createSerializer();
ser.array(src, [&ser](auto& v) {
ser.array(src, [](auto &s, auto& v) {
char tmp{};
ser.object(v).value1(tmp);
s.object(v).value1(tmp);
});
auto des = ctx.createDeserializer();
des.array(res, [&des](auto& v) {
des.array(res, [](auto &s, auto& v) {
char tmp{};
des.object(v).value1(tmp);
s.object(v).value1(tmp);
});
EXPECT_THAT(ctx.getBufferSize(), Eq(src.size() * (MyStruct1::SIZE + sizeof(char))));
EXPECT_THAT(res, ContainerEq(src));
}
TEST(SerializeFSArrayCArray, ArithmeticValues) {
SerializationContext ctx;
int src[4]{5,9,15,-459};
int res[4]{};
ctx.createSerializer().array(src);
ctx.createDeserializer().array(res);
EXPECT_THAT(ctx.getBufferSize(), Eq(std::extent<decltype(src)>::value * sizeof(int)));
EXPECT_THAT(res, ContainerEq(src));
}
TEST(SerializeFSArrayCArray, ArithmeticValuesSettingValueSizeExplicitly) {
SerializationContext ctx;
int src[4]{5,9,15,-459};
@@ -143,14 +116,14 @@ TEST(SerializeFSArrayCArray, CustomFunctionThatSerializesAnEmptyByteEveryElement
auto ser = ctx.createSerializer();
ser.array(src, [&ser](auto& v) {
ser.array(src, [](auto& s, auto& v) {
char tmp{};
ser.object(v).value1(tmp);
s.object(v).value1(tmp);
});
auto des = ctx.createDeserializer();
des.array(res, [&des](auto& v) {
des.array(res, [](auto& s, auto& v) {
char tmp{};
des.object(v).value1(tmp);
s.object(v).value1(tmp);
});
EXPECT_THAT(ctx.getBufferSize(), Eq(std::extent<decltype(src)>::value * (MyStruct1::SIZE + sizeof(char))));

View File

@@ -29,6 +29,8 @@
#include <list>
using testing::Eq;
using testing::StrEq;
using testing::ContainerEq;
@@ -69,15 +71,16 @@ SERIALIZE(X)
SERIALIZE(Y)
{
auto writeInt = [&s](auto& v) { s.template value<sizeof(v)>(v); };
auto writeInt = [](auto& s, auto& v) { s.template value<sizeof(v)>(v); };
s.template text<1>(o.s, 10000);
s.template value<sizeof(o.y)>(o.y);
s.array(o.arr, writeInt);
s.array(o.carr, writeInt);
s.container(o.vx, [&s](auto& v) { s.object(v); }, 10000);
s.container(o.vx, 10000, [](auto& s, auto& v) { s.object(v); });
return s;
}
TEST(SerializeObject, GeneralConceptTest) {
//std::string buf;
SerializationContext ctx;

View File

@@ -28,9 +28,9 @@ using testing::Eq;
bool SerializeDeserializeContainerSize(SerializationContext& ctx, const size_t size) {
std::vector<char> t1(size);
ctx.createSerializer().container(t1, [](auto ){}, size+1);
ctx.createSerializer().container(t1, size+1, [](auto , auto ){});
t1.clear();
ctx.createDeserializer().container(t1, [](auto ){}, size+1);
ctx.createDeserializer().container(t1, size+1, [](auto , auto ){});
return t1.size() == size;
}

View File

@@ -101,16 +101,16 @@ TEST(SerializeSubstitution, CustomFunctionNotSubstituted) {
auto ser = ctx.createSerializer();
//lambdas differ only in capture clauses, it would make sense to use std::bind, but debugger crashes when it sees std::bind...
auto serLambda = [&ser, rangeForValue](const MyStruct1& v) {
ser.range(v.i1, rangeForValue);
ser.range(v.i2, rangeForValue);
auto serLambda = [rangeForValue](auto& s, const MyStruct1& v) {
s.range(v.i1, rangeForValue);
s.range(v.i2, rangeForValue);
};
ser.substitution(v, subsitution, serLambda);
auto des = ctx.createDeserializer();
auto desLambda = [&des, rangeForValue](MyStruct1& v) {
des.range(v.i1, rangeForValue);
des.range(v.i2, rangeForValue);
auto desLambda = [rangeForValue](auto& s, MyStruct1& v) {
s.range(v.i1, rangeForValue);
s.range(v.i2, rangeForValue);
};
des.substitution(res, subsitution, desLambda);
@@ -127,8 +127,8 @@ TEST(SerializeSubstitution, WhenSubstitutedThenCustomFunctionNotInvoked) {
MyStruct1{4849,89}, MyStruct1{0,1}};
SerializationContext ctx;
ctx.createSerializer().substitution(v, subsitution, [](const MyStruct1& ) {});
ctx.createDeserializer().substitution(res, subsitution, [](MyStruct1& ) {});
ctx.createSerializer().substitution(v, subsitution, [](bitsery::Serializer<bitsery::BufferWriter>& ,const MyStruct1& ) {});
ctx.createDeserializer().substitution(res, subsitution, [](bitsery::Deserializer<bitsery::BufferReader>&, MyStruct1& ) {});
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));