DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
Serialization.hpp
Go to the documentation of this file.
1
17#ifndef SERIALIZATION_INCLUDE_SERIALIZATION_SERIALIZATION_HPP_
18#define SERIALIZATION_INCLUDE_SERIALIZATION_SERIALIZATION_HPP_
19
20#include "ers/Issue.hpp"
21#include "logging/Logging.hpp" // NOTE: if ISSUES ARE DECLARED BEFORE include logging/Logging.hpp, TLOG_DEBUG<<issue wont work.
22
23#include "boost/preprocessor.hpp"
24#include "msgpack.hpp"
25
26#include <algorithm>
27#include <string>
28#include <vector>
29
35// NOLINTNEXTLINE
36#define DUNE_DAQ_TYPESTRING(Type, typestring) \
37 template<> \
38 inline std::string dunedaq::datatype_to_string<Type>() \
39 { \
40 return typestring; \
41 }
42
46// NOLINTNEXTLINE
47#define DUNE_DAQ_SERIALIZABLE(Type, typestring) \
48 DUNE_DAQ_TYPESTRING(Type, typestring) \
49 template<> \
50 struct dunedaq::serialization::is_serializable<Type> \
51 { \
52 static constexpr bool value = true; \
53 }
54
72// NOLINTNEXTLINE
73#define DUNE_DAQ_SERIALIZE(Type, ...) \
74 MSGPACK_DEFINE(__VA_ARGS__) \
75 static_assert(true, "")
76
78// NOLINTNEXTLINE
79#define OPACK(r, data, elem) o.pack(m.elem);
81// NOLINTNEXTLINE
82#define OUNPACK(r, data, elem) m.elem = o.via.array.ptr[i++].as<decltype(m.elem)>();
83
104// NOLINTNEXTLINE
105#define DUNE_DAQ_SERIALIZE_NON_INTRUSIVE(NS, Type, ...) \
106 DUNE_DAQ_SERIALIZABLE(NS::Type, #Type); \
107 namespace msgpack { \
108 MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) \
109 { \
110 namespace adaptor { \
111 template<> \
112 struct pack<NS::Type> \
113 { \
114 template<typename Stream> \
115 packer<Stream>& operator()(msgpack::packer<Stream>& o, NS::Type const& m) const \
116 { \
117 o.pack_array(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)); \
118 BOOST_PP_SEQ_FOR_EACH(OPACK, , BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
119 return o; \
120 } \
121 }; \
122 template<> \
123 struct convert<NS::Type> \
124 { \
125 msgpack::object const& operator()(msgpack::object const& o, NS::Type& m) const \
126 { \
127 if (o.type != msgpack::type::ARRAY) \
128 throw msgpack::type_error(); \
129 if (o.via.array.size != BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)) \
130 throw msgpack::type_error(); \
131 int i = 0; \
132 BOOST_PP_SEQ_FOR_EACH(OUNPACK, , BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
133 return o; \
134 } \
135 }; \
136 } \
137 } \
138 }
139
143// NOLINTNEXTLINE
144#define DUNE_DAQ_SERIALIZE_ENUM(Type) MSGPACK_ADD_ENUM(Type)
145
146namespace dunedaq {
147
148// Disable coverage collection LCOV_EXCL_START
150ERS_DECLARE_ISSUE(serialization, UnknownSerializationTypeString, "Unknown serialization type " << t, ((std::string)t))
152ERS_DECLARE_ISSUE(serialization, UnknownSerializationTypeEnum, "Unknown serialization type", )
154ERS_DECLARE_ISSUE(serialization, UnknownSerializationTypeByte, "Unknown serialization type " << t, ((char)t)) // NOLINT
156ERS_DECLARE_ISSUE(serialization, CannotDeserializeMessage, "Cannot deserialize message", )
157// Re-enable coverage collection LCOV_EXCL_STOP
158
159template<typename T>
160inline std::string
161datatype_to_string()
162{
163 return "Unknown";
164}
165
166namespace serialization {
167
168template<typename T>
169struct is_serializable : std::false_type
170{};
171
175enum SerializationType
176{
177 kMsgPack
178};
179
183inline SerializationType
184from_string(const std::string s)
185{
186 if (s == "msgpack")
187 return kMsgPack;
188 throw UnknownSerializationTypeString(ERS_HERE, s);
189}
190
191constexpr uint8_t // NOLINT(build/unsigned)
192serialization_type_byte(SerializationType stype)
193{
194 switch (stype) {
195 case kMsgPack:
196 return 'M';
197 default:
198 throw UnknownSerializationTypeEnum(ERS_HERE);
199 }
200}
201
202constexpr SerializationType DEFAULT_SERIALIZATION_TYPE = kMsgPack;
203
207template<class T>
208std::vector<uint8_t> // NOLINT(build/unsigned)
209serialize(const T& obj, SerializationType stype = DEFAULT_SERIALIZATION_TYPE)
210{
211 switch (stype) {
212 case kMsgPack: {
213 // Serialize into the sbuffer and then copy to a
214 // std::vector. Seems like it would be more efficient to
215 // write directly to the vector (by creating a class that
216 // implements `void write(char* buf, size_t len)`), but my
217 // tests aren't any faster than this
218 msgpack::sbuffer buf;
219 msgpack::pack(buf, obj);
220 std::vector<uint8_t> ret(buf.size() + 1); // NOLINT(build/unsigned)
221 ret[0] = serialization_type_byte(stype);
222 std::copy(buf.data(), buf.data() + buf.size(), ret.begin() + 1); // NOLINT
223 return ret;
224 }
225 default:
226 throw UnknownSerializationTypeEnum(ERS_HERE);
227 }
228}
229
233template<class T, typename CharType = unsigned char>
234T
235deserialize(const std::vector<CharType>& v)
236{
237 // The first byte in the array indicates the serialization format;
238 // the rest is the actual message
239 switch (v[0]) {
240 case serialization_type_byte(kMsgPack): {
241 try {
242 // The lambda function here is of type `unpack_reference_func`
243 // as described at
244 // https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_unpacker#memory-management
245 // . It is called for every STR, BIN and EXT field in the
246 // MsgPack data. If the function returns false, the object is
247 // copied into MsgPack's "zone", otherwise a pointer to the
248 // original buffer is stored. Our input buffer is going to exist
249 // at least until the end of this function, so it's safe to
250 // return true (ie, store a pointer in the MsgPack object; no
251 // copy) everywhere. Doing so results in a factor ~2 speedup in
252 // deserializing Fragment, which is just a large BIN field
253 msgpack::object_handle oh = msgpack::unpack(
254 const_cast<char*>(reinterpret_cast<const char*>(v.data() + 1)), // NOLINT
255 v.size() - 1,
256 [](msgpack::type::object_type /*typ*/, std::size_t /*length*/, void* /*user_data*/) -> bool { return true; });
257 msgpack::object obj = oh.get();
258 return obj.as<T>();
259 } catch (msgpack::type_error& e) {
260 throw CannotDeserializeMessage(ERS_HERE, e);
261 } catch (msgpack::unpack_error& e) {
262 throw CannotDeserializeMessage(ERS_HERE, e);
263 }
264 }
265 default:
266 throw UnknownSerializationTypeByte(ERS_HERE, (char)v[0]); // NOLINT
267 }
268}
269
270} // namespace serialization
271} // namespace dunedaq
272
273#endif // SERIALIZATION_INCLUDE_SERIALIZATION_SERIALIZATION_HPP_
#define ERS_DECLARE_ISSUE(namespace_name, class_name, message, attributes)
#define ERS_HERE
The DUNE-DAQ namespace.
Definition DataStore.hpp:57
msgpack::object obj
UnknownSerializationTypeByte
default char v[0]