DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
serialize_variant.hpp
Go to the documentation of this file.
1
14#ifndef SERIALIZATION_INCLUDE_SERIALIZATION_SERIALIZE_VARIANT_HPP_
15#define SERIALIZATION_INCLUDE_SERIALIZATION_SERIALIZE_VARIANT_HPP_
16
17#include "msgpack.hpp"
18
19#include <iostream>
20#include <utility>
21#include <variant>
22
23namespace msgpack {
24MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS)
25{
26 namespace adaptor {
27
28 template<typename... Args>
29 struct pack<std::variant<Args...>>
30 {
31 template<typename Stream>
32 packer<Stream>& operator()(msgpack::packer<Stream>& o, std::variant<Args...> const& v) const
33 {
34 // There are always exactly 2 items in the msgpack array: the
35 // index indicating which type the variant is holding, and the
36 // instance of the type itself (it *doesn't* depend sizeof...(Args))
37 o.pack_array(2);
38 o.pack(v.index());
39 std::visit([&o](auto&& arg) { o.pack(arg); }, v);
40 return o;
41 }
42 };
43
44 template<typename... Args>
45 struct convert<std::variant<Args...>>
46 {
47
48 // Base case for the variadic template function below. Should never be
49 // called, but the compiler needs to see it
50 template<typename VariantType>
51 void set_variant_helper(std::size_t, msgpack::object const&, VariantType&&) const
52 {}
53
54 // Deserializing std::variant is tricky, because we only know the
55 // index of the type that's held at runtime. We want something that is effectively:
56 //
57 // std::variant<T0, T1, T2, ...> v;
58 // size_t index = deserialize index...;
59 // switch(index){
60 // case 0:
61 // v = o.via.array.ptr.as<T0>(); break
62 // case 1:
63 // v = o.via.array.ptr.as<T1>(); break
64 // ...etc...
65 //
66 // This recursive variadic template function achieves that, using
67 // the index as a regular function parameter (not a template
68 // parameter, since it's only known at runtime). We peel off the
69 // variant types one at a time, decreasing the index each time. When
70 // the index reaches zero, we've peeled off enough types to get the
71 // one we want, so we can set the std::variant
72 template<typename VariantType, typename T, typename... Types>
73 void set_variant_helper(std::size_t i, msgpack::object const& o, VariantType&& v) const
74 {
75 if (i == 0)
76 v = o.via.array.ptr[1].as<T>();
77 else
78 set_variant_helper<VariantType, Types...>(i - 1, o, v);
79 }
80
81 msgpack::object const& operator()(msgpack::object const& o, std::variant<Args...>& v) const
82 {
83 if (o.type != msgpack::type::ARRAY)
84 throw msgpack::type_error();
85 // There are always exactly 2 items in the msgpack array: the
86 // index indicating which type the variant is holding, and the
87 // instance of the type itself (it *doesn't* depend sizeof...(Args))
88 if (o.via.array.size != 2)
89 throw msgpack::type_error();
90 std::size_t index = o.via.array.ptr[0].as<std::size_t>();
91 if (index >= sizeof...(Args)) {
92 throw msgpack::type_error();
93 }
94 set_variant_helper<std::variant<Args...>&, Args...>(index, o, v);
95 return o;
96 }
97 };
98
99 } // namespace adaptor
100} // MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS)
101} // namespace msgpack
102
103#endif // SERIALIZATION_INCLUDE_SERIALIZATION_SERIALIZE_VARIANT_HPP_
MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS)