Skip to content

Commit

Permalink
Merge pull request #2729 from div72/serialize-variant
Browse files Browse the repository at this point in the history
serialize: allow variants to be serialized
  • Loading branch information
jamescowens authored Dec 26, 2023
2 parents 67ab7fb + 97b5572 commit e01fd09
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 0 deletions.
45 changes: 45 additions & 0 deletions src/serialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <string>
#include <string.h>
#include <utility>
#include <variant>
#include <vector>

#include <prevector.h>
Expand Down Expand Up @@ -724,6 +725,10 @@ template<typename Stream, typename T> void Unserialize(Stream& os, std::shared_p
template<typename Stream, typename T> void Serialize(Stream& os, const std::unique_ptr<const T>& p);
template<typename Stream, typename T> void Unserialize(Stream& os, std::unique_ptr<const T>& p);

// variant
template<typename Stream, class... Args> void Serialize(Stream& os, const std::variant<Args...>& v);
template<typename Stream, class... Args> void Unserialize(Stream& is, const std::variant<Args...>& v);



/**
Expand Down Expand Up @@ -1071,6 +1076,46 @@ void Unserialize(Stream& is, std::shared_ptr<const T>& p)



// variant
template<typename Stream, class... Args>
void Serialize(Stream& os, const std::variant<Args...>& v) {
// The 253 limit here is for that if there's a need for more than 253 type variant in the
// future, someone can replace the index uint8 with a var-int without sacrificing backwards
// compatibility.
static_assert(sizeof...(Args) < 253, "variants should hold less than 253 types.");

Serialize(os, (uint8_t)v.index());

std::visit([&](auto& v2) { Serialize(os, v2); }, v);
}

template<typename Stream, uint64_t n, typename V>
void unserialize_variant_helper(Stream& is, uint8_t index, V& v) {}

template<typename Stream, uint64_t n, typename V, typename T, class... Args>
void unserialize_variant_helper(Stream& is, uint8_t index, V& v) {
if (index == n) {
T o;
Unserialize(is, o);
v = o;
} else {
unserialize_variant_helper<Stream, n + 1, V, Args...>(is, index, v);
}
}

template<typename Stream, class... Args>
void Unserialize(Stream& is, std::variant<Args...>& v) {
// The 253 limit here is for that if there's a need for more than 253 type variant in the
// future, someone can replace the index uint8 with a var-int without sacrificing backwards
// compatibility.
static_assert(sizeof...(Args) < 253, "variants should hold less than 253 types.");

uint8_t index;
Unserialize(is, index);

unserialize_variant_helper<Stream, 0, std::variant<Args...>, Args...>(is, index, v);
}

/**
* Support for ADD_SERIALIZE_METHODS and READWRITE macro
*/
Expand Down
32 changes: 32 additions & 0 deletions src/test/serialize_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,4 +330,36 @@ BOOST_AUTO_TEST_CASE(class_methods)
BOOST_CHECK(methodtest3 == methodtest4);
}

BOOST_AUTO_TEST_CASE(variants)
{
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
using p_t = std::pair<int, int>;
std::variant<int, std::string, double, p_t, CSerializeMethodsTestSingle> v;
CTransaction txval;
const char charstrval[16] = "testing charstr";
CSerializeMethodsTestSingle csmts(-3, false, "testing", charstrval, txval);

v = 42;
ss << v;
v = "sel";
ss << v;
v = 3.1415;
ss << v;
v = std::make_pair(14, 48);
ss << v;
v = csmts;
ss << v;

ss >> v;
BOOST_CHECK_EQUAL(std::get<int>(v), 42);
ss >> v;
BOOST_CHECK_EQUAL(std::get<std::string>(v), "sel");
ss >> v;
BOOST_CHECK_EQUAL(std::get<double>(v), 3.1415);
ss >> v;
BOOST_CHECK(std::get<p_t>(v) == std::make_pair(14, 48));
ss >> v;
BOOST_CHECK(std::get<CSerializeMethodsTestSingle>(v) == csmts);
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit e01fd09

Please sign in to comment.