DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
Serialization.hpp
Go to the documentation of this file.
1
16
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// NOLINTBEGIN
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#define DUNE_DAQ_SERIALIZABLE(Type, typestring) \
47 DUNE_DAQ_TYPESTRING(Type, typestring) \
48 template<> \
49 struct dunedaq::serialization::is_serializable<Type> \
50 { \
51 static constexpr bool value = true; \
52 }
53
71#define DUNE_DAQ_SERIALIZE(Type, ...) \
72 MSGPACK_DEFINE(__VA_ARGS__) \
73 static_assert(true, "")
74
76#define OPACK(r, data, elem) o.pack(m.elem);
78#define OUNPACK(r, data, elem) m.elem = o.via.array.ptr[i++].as<decltype(m.elem)>();
79
100#define DUNE_DAQ_SERIALIZE_NON_INTRUSIVE(NS, Type, ...) \
101 DUNE_DAQ_SERIALIZABLE(NS::Type, #Type); \
102 namespace msgpack { \
103 MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) \
104 { \
105 namespace adaptor { \
106 template<> \
107 struct pack<NS::Type> \
108 { \
109 template<typename Stream> \
110 packer<Stream>& operator()(msgpack::packer<Stream>& o, NS::Type const& m) const \
111 { \
112 o.pack_array(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)); \
113 BOOST_PP_SEQ_FOR_EACH(OPACK, , BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
114 return o; \
115 } \
116 }; \
117 template<> \
118 struct convert<NS::Type> \
119 { \
120 msgpack::object const& operator()(msgpack::object const& o, NS::Type& m) const \
121 { \
122 if (o.type != msgpack::type::ARRAY) \
123 throw msgpack::type_error(); \
124 if (o.via.array.size != BOOST_PP_VARIADIC_SIZE(__VA_ARGS__)) \
125 throw msgpack::type_error(); \
126 int i = 0; \
127 BOOST_PP_SEQ_FOR_EACH(OUNPACK, , BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
128 return o; \
129 } \
130 }; \
131 } \
132 } \
133 } // namespace msgpack
134
138#define DUNE_DAQ_SERIALIZE_ENUM(Type) MSGPACK_ADD_ENUM(Type)
139// NOLINTEND
140
141namespace dunedaq {
142
143// Disable coverage collection LCOV_EXCL_START
145ERS_DECLARE_ISSUE(serialization, UnknownSerializationTypeString, "Unknown serialization type " << t, ((std::string)t))
147ERS_DECLARE_ISSUE(serialization, UnknownSerializationTypeEnum, "Unknown serialization type", )
149ERS_DECLARE_ISSUE(serialization, UnknownSerializationTypeByte, "Unknown serialization type " << t, ((char)t)) // NOLINT
151ERS_DECLARE_ISSUE(serialization, CannotDeserializeMessage, "Cannot deserialize message", )
152// Re-enable coverage collection LCOV_EXCL_STOP
153
154template<typename T>
155inline std::string
156datatype_to_string()
157{
158 return "Unknown";
159}
160
161namespace serialization {
162
163template<typename T>
164struct is_serializable : std::false_type
165{};
166
170enum SerializationType
171{
172 kMsgPack
173};
174
178inline SerializationType
179from_string(const std::string s)
180{
181 if (s == "msgpack")
182 return kMsgPack;
183 throw UnknownSerializationTypeString(ERS_HERE, s);
184}
185
186constexpr uint8_t // NOLINT(build/unsigned)
187serialization_type_byte(SerializationType stype)
188{
189 switch (stype) {
190 case kMsgPack:
191 return 'M';
192 default:
193 throw UnknownSerializationTypeEnum(ERS_HERE);
194 }
195}
196
197constexpr SerializationType DEFAULT_SERIALIZATION_TYPE = kMsgPack;
198
202template<class T>
203std::vector<uint8_t> // NOLINT(build/unsigned)
204serialize(const T& obj, SerializationType stype = DEFAULT_SERIALIZATION_TYPE)
205{
206 switch (stype) {
207 case kMsgPack: {
208 // Serialize into the sbuffer and then copy to a
209 // std::vector. Seems like it would be more efficient to
210 // write directly to the vector (by creating a class that
211 // implements `void write(char* buf, size_t len)`), but my
212 // tests aren't any faster than this
213 msgpack::sbuffer buf;
214 msgpack::pack(buf, obj);
215 std::vector<uint8_t> ret(buf.size() + 1); // NOLINT(build/unsigned)
216 ret[0] = serialization_type_byte(stype);
217 std::copy(buf.data(), buf.data() + buf.size(), ret.begin() + 1); // NOLINT
218 return ret;
219 }
220 default:
221 throw UnknownSerializationTypeEnum(ERS_HERE);
222 }
223}
224
228template<class T, typename CharType = unsigned char>
229T
230deserialize(const std::vector<CharType>& v)
231{
232 // The first byte in the array indicates the serialization format;
233 // the rest is the actual message
234 switch (v[0]) {
235 case serialization_type_byte(kMsgPack): {
236 try {
237 // The lambda function here is of type `unpack_reference_func`
238 // as described at
239 // https://github.com/msgpack/msgpack-c/wiki/v2_0_cpp_unpacker#memory-management
240 // . It is called for every STR, BIN and EXT field in the
241 // MsgPack data. If the function returns false, the object is
242 // copied into MsgPack's "zone", otherwise a pointer to the
243 // original buffer is stored. Our input buffer is going to exist
244 // at least until the end of this function, so it's safe to
245 // return true (ie, store a pointer in the MsgPack object; no
246 // copy) everywhere. Doing so results in a factor ~2 speedup in
247 // deserializing Fragment, which is just a large BIN field
248 msgpack::object_handle oh = msgpack::unpack(
249 const_cast<char*>(reinterpret_cast<const char*>(v.data() + 1)), // NOLINT
250 v.size() - 1,
251 [](msgpack::type::object_type /*typ*/, std::size_t /*length*/, void* /*user_data*/) -> bool { return true; });
252 msgpack::object obj = oh.get();
253 return obj.as<T>();
254 } catch (msgpack::type_error& e) {
255 throw CannotDeserializeMessage(ERS_HERE, e);
256 } catch (msgpack::unpack_error& e) {
257 throw CannotDeserializeMessage(ERS_HERE, e);
258 }
259 }
260 default:
261 throw UnknownSerializationTypeByte(ERS_HERE, (char)v[0]); // NOLINT
262 }
263}
264
265} // namespace serialization
266} // namespace dunedaq
267
268#endif // SERIALIZATION_INCLUDE_SERIALIZATION_SERIALIZATION_HPP_
#define ERS_HERE
The DUNE-DAQ namespace.
msgpack::object obj
UnknownSerializationTypeByte
ERS_DECLARE_ISSUE(cibmodules, CIBCommunicationError, " CIB Hardware Communication Error: "<< descriptor,((std::string) descriptor)) ERS_DECLARE_ISSUE(cibmodules
default char v[0]