From ca62563df341786d1d1809a037d8b592924e78c4 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 8 Jan 2020 08:56:19 -0800 Subject: [PATCH] Add a generic approach for (de)serialization of objects using code in other classes This adds the (internal) Wrapper class, and the Using function that uses it. Given a class F that implements Ser(stream, const object&) and Unser(stream, object&) functions, this permits writing e.g. READWRITE(Using(object)). --- src/serialize.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/serialize.h b/src/serialize.h index c9e994f844..fd8626007a 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -442,6 +442,32 @@ I ReadVarInt(Stream& is) } } +/** Simple wrapper class to serialize objects using a formatter; used by Using(). */ +template +class Wrapper +{ + static_assert(std::is_lvalue_reference::value, "Wrapper needs an lvalue reference type T"); +protected: + T m_object; +public: + explicit Wrapper(T obj) : m_object(obj) {} + template void Serialize(Stream &s) const { Formatter().Ser(s, m_object); } + template void Unserialize(Stream &s) { Formatter().Unser(s, m_object); } +}; + +/** Cause serialization/deserialization of an object to be done using a specified formatter class. + * + * To use this, you need a class Formatter that has public functions Ser(stream, const object&) for + * serialization, and Unser(stream, object&) for deserialization. Serialization routines (inside + * READWRITE, or directly with << and >> operators), can then use Using(object). + * + * This works by constructing a Wrapper-wrapped version of object, where T is + * const during serialization, and non-const during deserialization, which maintains const + * correctness. + */ +template +static inline Wrapper Using(T&& t) { return Wrapper(t); } + #define VARINT(obj, ...) WrapVarInt<__VA_ARGS__>(REF(obj)) #define COMPACTSIZE(obj) CCompactSize(REF(obj)) #define LIMITED_STRING(obj,n) LimitedString< n >(REF(obj))