CCF
Loading...
Searching...
No Matches
serializer.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
5#include "ccf/ds/nonstd.h"
6#include "serialized.h"
7
8#include <memory>
9#include <span>
10#include <tuple>
11#include <type_traits>
12#include <vector>
13
14namespace serializer
15{
16 // A Serializer is generally used as a template argument. It should provide:
17 // - serialize(...): returning a tuple of PartialSerializations representing
18 // all passed args. It may be templated and variadic or accept only precise
19 // argument types. Ideally it should give a useful error message at compile
20 // time when called with argument types it doesn't support.
21 // - deserialize(const uint8_t* data, size_t size): returning a tuple of
22 // elements parsed from byte buffer, potentially throwing logic errors if
23 // anything is missing/malformed. May need to be templated on expected
24 // types.
25
26 struct ByteRange
27 {
28 const uint8_t* data;
29 const size_t size;
30
31 operator std::span<const uint8_t>() const
32 {
33 return {data, size};
34 }
35 };
36
37 namespace details
38 {
41 template <size_t I = 0, typename F, typename... Ts>
42 static auto tuple_apply(const std::tuple<Ts...>& t, const F& f)
43 {
44 if constexpr (sizeof...(Ts) == 1)
45 {
46 return std::make_tuple();
47 }
48 else if constexpr (I == sizeof...(Ts) - 1)
49 {
50 return f(std::get<I>(t));
51 }
52 else
53 {
54 return std::tuple_cat(f(std::get<I>(t)), tuple_apply<I + 1>(t, f));
55 }
56 }
57
58 template <typename Tup>
60 {
61 static constexpr size_t TupSize = std::tuple_size_v<Tup>;
62
63 template <typename... Ts>
65 {
66 static constexpr bool value = TupSize == sizeof...(Ts);
67 };
68
69 template <typename... Ts>
70 static constexpr bool correct_size_v = correct_size<Ts...>::value;
71
72 template <size_t I, typename T>
74 {
76 std::remove_cvref_t<typename std::tuple_element_t<I, Tup>>;
77 using CanonArgument = std::remove_cvref_t<T>;
78
79 // This determines what types a Serializer will accept as arguments to
80 // serialize(...), relative to the declared param types.
81 // The main feature is the removal of const, volatile, and references
82 // from the type so that a Serializer<int> will accept an argument of
83 // type const int&.
84 // Additionally, this will accept ByteRange arguments for parameters
85 // declared as std::vector<uint8_t> and vice versa - when serializing we
86 // can copy bytes from either in the same way, but there is a
87 // distinction in the deserialized type of whether we are copying (to a
88 // byte vector) or referring to an existing byte range. It may be
89 // possible to generalise this further and replace with
90 // std::is_constructible, but these restrictions are sufficient for the
91 // current uses.
92 // Additionally again, this will accept an array-like of ByteRanges for
93 // a single ByteRange parameter. These will be serialised in-order, and
94 // produce a single ByteRange in deserialisation.
95 static constexpr bool value =
96 std::is_same_v<CanonTarget, CanonArgument> ||
97 (std::is_same_v<CanonTarget, std::vector<uint8_t>> &&
98 std::is_same_v<CanonArgument, ByteRange>) ||
99 (std::is_same_v<CanonTarget, ByteRange> &&
100 std::is_same_v<CanonArgument, std::vector<uint8_t>>) ||
101 (std::is_same_v<CanonTarget, ByteRange> &&
102 (std::is_array_v<CanonArgument> &&
103 std::is_same_v<std::remove_extent_t<CanonArgument>, ByteRange>));
104 };
105
106 // Only reached when Ts is empty
107 template <size_t I, typename... Ts>
109 {
110 static constexpr bool value = I == TupSize;
111 };
112
113 template <size_t I, typename T, typename... Ts>
114 struct close_enough_from<I, T, Ts...>
115 {
116 static constexpr bool value = close_enough_at<I, T>::value &&
117 close_enough_from<I + 1, Ts...>::value;
118 };
119
120 template <typename... Ts>
122 {
123 static constexpr bool value = close_enough_from<0, Ts...>::value;
124 };
125
126 template <typename... Ts>
127 static constexpr bool close_enough_v = close_enough<Ts...>::value;
128 };
129
130 template <typename... Ts>
131 struct TypeMatcher : public TupMatcher<std::tuple<Ts...>>
132 {};
133 }
134
136 {
137 virtual ~AbstractSerializedSection() = default;
138 [[nodiscard]] virtual const uint8_t* data() const = 0;
139 [[nodiscard]] virtual size_t size() const = 0;
140 };
141
142 using PartialSerialization = std::shared_ptr<AbstractSerializedSection>;
143
144 template <typename T>
146 {
147 const T t;
148
149 CopiedSection(const T& t_) : t(t_) {}
150
151 [[nodiscard]] const uint8_t* data() const override
152 {
153 return reinterpret_cast<const uint8_t*>(&t);
154 }
155
156 [[nodiscard]] size_t size() const override
157 {
158 return sizeof(T);
159 }
160 };
161
162 template <typename T>
164 {
165 const T& t;
166
167 RawSection(const T& t_) : t(t_) {}
168
169 [[nodiscard]] const uint8_t* data() const override
170 {
171 return reinterpret_cast<const uint8_t*>(&t);
172 }
173
174 [[nodiscard]] size_t size() const override
175 {
176 return sizeof(T);
177 }
178 };
179
181 {
182 const uint8_t* const d;
183 const size_t s;
184
185 MemoryRegionSection(const uint8_t* data_, size_t size_) : d(data_), s(size_)
186 {}
187
188 [[nodiscard]] const uint8_t* data() const override
189 {
190 return d;
191 }
192
193 [[nodiscard]] size_t size() const override
194 {
195 return s;
196 }
197 };
198
200 {
201 public:
203 template <typename... Ts>
204 static std::tuple<> serialize(const Ts&... ts)
205 {
206 static_assert(
207 sizeof...(ts) == 0,
208 "EmptySerializer was given message payload to serialize - can only "
209 "serialize empty "
210 "messages");
211 return std::make_tuple();
212 }
213
214 template <typename... Ts>
215 static std::tuple<> deserialize(const uint8_t* /*unused*/, size_t size)
216 {
217 if constexpr (sizeof...(Ts) == 0)
218 {
219 if (size > 0)
220 {
221 throw std::logic_error(
222 "EmptySerializer asked to deserialize buffer of size " +
223 std::to_string(size) + ", should be empty");
224 }
225 }
226 return std::make_tuple();
227 }
228 };
229
231 {
232 template <size_t N, size_t... Is>
233 static auto serialize_byte_range_with_index_sequence(
234 const ByteRange (&brs)[N], std::index_sequence<Is...> /*unused*/)
235 {
236 return std::make_tuple(
237 std::make_shared<MemoryRegionSection>(brs[Is].data, brs[Is].size)...);
238 }
239
243 static auto serialize_value(const ByteRange& br)
244 {
245 auto cs = std::make_shared<CopiedSection<size_t>>(br.size);
246 auto bfs = std::make_shared<MemoryRegionSection>(br.data, br.size);
247 return std::tuple_cat(std::make_tuple(cs), std::make_tuple(bfs));
248 }
249
252 template <size_t N>
253 static auto serialize_value(const ByteRange (&brs)[N])
254 {
255 return serialize_byte_range_with_index_sequence(
256 brs, std::make_index_sequence<N>{});
257 }
258
260 static auto serialize_value(const std::vector<uint8_t>& vec)
261 {
262 auto cs = std::make_shared<CopiedSection<size_t>>(vec.size());
263 auto bfs = std::make_shared<MemoryRegionSection>(vec.data(), vec.size());
264 return std::tuple_cat(std::make_tuple(cs), std::make_tuple(bfs));
265 }
266
270 static auto serialize_value(std::span<uint8_t> s)
271 {
272 auto csd = std::make_shared<CopiedSection<uintptr_t>>(
273 reinterpret_cast<std::uintptr_t>(s.data()));
274 auto css = std::make_shared<CopiedSection<size_t>>(s.size());
275 return std::tuple_cat(std::make_tuple(csd), std::make_tuple(css));
276 }
277
279 static auto serialize_value(const std::string& s)
280 {
281 auto cs = std::make_shared<CopiedSection<size_t>>(s.size());
282 auto bfs = std::make_shared<MemoryRegionSection>(
283 reinterpret_cast<const uint8_t*>(s.data()), s.size());
284 return std::tuple_cat(std::make_tuple(cs), std::make_tuple(bfs));
285 }
286
288 template <typename T>
289 requires(std::is_integral_v<T> || std::is_enum_v<T>)
290 static auto serialize_value(const T& t)
291 {
292 auto rs = std::make_shared<RawSection<T>>(t);
293 return std::make_tuple(rs);
294 }
296
301 static auto serialize_value_final(const ByteRange& br)
302 {
303 auto bfs = std::make_shared<MemoryRegionSection>(br.data, br.size);
304 return std::make_tuple(bfs);
305 }
306
309 static auto serialize_value_final(const std::vector<uint8_t>& vec)
310 {
311 auto bfs = std::make_shared<MemoryRegionSection>(vec.data(), vec.size());
312 return std::make_tuple(bfs);
313 }
314
316 template <typename T>
317 static auto serialize_value_final(const T& t)
318 {
319 return serialize_value(t);
320 }
322
324 template <typename T>
325 struct Tag
326 {
327 using type = T;
328 };
329
333 static ByteRange deserialize_value(
334 const uint8_t*& data, size_t& size, const Tag<ByteRange>& /*unused*/)
335 {
336 const auto prefixed_size = serialized::read<size_t>(data, size);
337 ByteRange br{data, prefixed_size};
338 serialized::skip(data, size, prefixed_size);
339 return br;
340 }
341
343 static std::vector<uint8_t> deserialize_value(
344 const uint8_t*& data,
345 size_t& size,
346 const Tag<std::vector<uint8_t>>& /*unused*/)
347 {
348 const auto prefixed_size = serialized::read<size_t>(data, size);
349 return serialized::read(data, size, prefixed_size);
350 }
351
353 static std::span<uint8_t> deserialize_value(
354 const uint8_t*& data,
355 size_t& size,
356 const Tag<std::span<uint8_t>>& /*unused*/)
357 {
358 const auto ptr = serialized::read<uintptr_t>(data, size);
359 const auto s = serialized::read<size_t>(data, size);
360 return {reinterpret_cast<uint8_t*>(ptr), s};
361 }
362
364 static std::string deserialize_value(
365 const uint8_t*& data, size_t& size, const Tag<std::string>& /*unused*/)
366 {
367 return serialized::read<std::string>(data, size);
368 }
369
371 template <typename T>
372 requires(std::is_integral_v<T> || std::is_enum_v<T>)
373 static T deserialize_value(
374 const uint8_t*& data, size_t& size, const Tag<T>& /*unused*/)
375 {
376 return serialized::read<T>(data, size);
377 }
379
383 static auto deserialize_value_final(
384 const uint8_t*& data, size_t& size, const Tag<ByteRange>& /*unused*/)
385 {
386 ByteRange br{data, size};
387 serialized::skip(data, size, size);
388 return br;
389 }
390
392 static auto deserialize_value_final(
393 const uint8_t*& data,
394 size_t& size,
395 const Tag<std::vector<uint8_t>>& /*unused*/)
396 {
397 return serialized::read(data, size, size);
398 }
399
401 template <typename T>
402 static T deserialize_value_final(
403 const uint8_t*& data, size_t& size, const Tag<T>& tag)
404 {
405 return deserialize_value(data, size, tag);
406 }
408
409 template <typename T, typename... Ts>
410 static auto deserialize_impl(const uint8_t* data, size_t size)
411 {
412 using StrippedT = std::remove_cvref_t<T>;
413
414 if constexpr (sizeof...(Ts) == 0)
415 {
416 return std::make_tuple(
417 deserialize_value_final(data, size, Tag<StrippedT>{}));
418 }
419 else
420 {
421 const auto next =
422 std::make_tuple(deserialize_value(data, size, Tag<StrippedT>{}));
423 return std::tuple_cat(next, deserialize_impl<Ts...>(data, size));
424 }
425 }
426
427 public:
428 // Can also serialize empty messages
430
433 template <typename T, typename... Ts>
434 static auto serialize(T&& t, Ts&&... ts)
435 {
436 if constexpr (sizeof...(Ts) == 0)
437 {
438 return serialize_value_final(std::forward<T>(t));
439 }
440 else
441 {
442 const auto next = serialize_value(std::forward<T>(t));
443 return std::tuple_cat(next, serialize(std::forward<Ts>(ts)...));
444 }
445 }
446
447 template <typename... Ts>
448 static auto deserialize(const uint8_t* data, size_t size)
449 {
450 if constexpr (sizeof...(Ts) == 0)
451 {
452 return EmptySerializer::deserialize(data, size);
453 }
454 else
455 {
456 return deserialize_impl<Ts...>(data, size);
457 }
458 }
459 };
460
461 // Serializes a list of exactly these argument types, and nothing else
462 template <typename... Us>
464 {
465 using Matcher = details::TypeMatcher<Us...>;
466
467 public:
468 template <typename... Ts>
469 static auto serialize(Ts&&... ts)
470 {
471 static_assert(
472 Matcher::template correct_size_v<Ts...>,
473 "Incorrect number of arguments for PreciseSerializer");
474 static_assert(
475 Matcher::template close_enough_v<Ts...>,
476 "Incorrect type of arguments for PreciseSerializer");
477
478 return CommonSerializer::serialize(std::forward<Ts>(ts)...);
479 }
480
481 template <typename... Ts>
482 static auto deserialize(const uint8_t* data, size_t size)
483 {
484 static_assert(
485 Matcher::template correct_size_v<Ts...>,
486 "Incorrect number of results for PreciseSerializer");
487 static_assert(
488 Matcher::template close_enough_v<Ts...>,
489 "Incorrect type of results for PreciseSerializer");
490
491 return CommonSerializer::deserialize<Us...>(data, size);
492 }
493
494 static auto deserialize(const uint8_t* data, size_t size)
495 {
496 return CommonSerializer::deserialize<Us...>(data, size);
497 }
498 };
499
500 template <typename>
502
503 // Specializes a specific tuple-type only. Removes ref and const when
504 // comparing types, ie tuple<int, const float&> will be accepted by
505 // TupleSerializers specialized at tuple<int, float>, tuple<const int&, const
506 // float&> etc
507 template <typename... Us>
508 class TupleSerializer<std::tuple<Us...>> : private CommonSerializer
509 {
510 using Tup = std::tuple<Us...>;
512
513 public:
514 template <typename... Ts>
515 static auto serialize(std::tuple<Ts...>&& t)
516 {
517 static_assert(
518 Matcher::template correct_size_v<Ts...>,
519 "Incorrect tuple size for TupleSerializer");
520 static_assert(
521 Matcher::template close_enough_v<Ts...>,
522 "Incorrect tuple type for TupleSerializer");
523
524 return details::tuple_apply(
525 t, [](const auto& e) { return CommonSerializer::serialize(e); });
526 }
527
528 // Takes variadic arguments list, they don't need to be packed in tuple
529 template <typename... Ts>
530 static auto serialize(Ts&&... ts)
531 {
532 static_assert(
533 Matcher::template correct_size_v<Ts...>,
534 "Incorrect number of args for unpacked TupleSerializer");
535 static_assert(
536 Matcher::template close_enough_v<Ts...>,
537 "Incorrect arg types for unpacked TupleSerializer");
538
539 return CommonSerializer::serialize(std::forward<Ts>(ts)...);
540 }
541
542 template <typename... Ts>
543 static auto deserialize(const uint8_t* data, size_t size)
544 {
545 static_assert(
546 Matcher::template correct_size_v<Ts...>,
547 "Incorrect number of results for TupleSerializer");
548 static_assert(
549 Matcher::template close_enough_v<Ts...>,
550 "Incorrect type of results for TupleSerializer");
551
552 return CommonSerializer::deserialize<Ts...>(data, size);
553 }
554
555 static auto deserialize(const uint8_t* data, size_t size)
556 {
557 return CommonSerializer::deserialize<Us...>(data, size);
558 }
559 };
560} // namespace serializer
Definition serializer.h:231
static auto deserialize(const uint8_t *data, size_t size)
Definition serializer.h:448
static auto serialize(T &&t, Ts &&... ts)
Definition serializer.h:434
Definition serializer.h:200
static std::tuple deserialize(const uint8_t *, size_t size)
Definition serializer.h:215
static std::tuple serialize(const Ts &... ts)
Can serialize empty messages, but nothing else.
Definition serializer.h:204
Definition serializer.h:464
static auto deserialize(const uint8_t *data, size_t size)
Definition serializer.h:494
static auto deserialize(const uint8_t *data, size_t size)
Definition serializer.h:482
static auto serialize(Ts &&... ts)
Definition serializer.h:469
static auto deserialize(const uint8_t *data, size_t size)
Definition serializer.h:555
static auto serialize(Ts &&... ts)
Definition serializer.h:530
static auto serialize(std::tuple< Ts... > &&t)
Definition serializer.h:515
static auto deserialize(const uint8_t *data, size_t size)
Definition serializer.h:543
Definition serializer.h:501
void skip(const uint8_t *&data, size_t &size, size_t skip)
Definition serialized.h:165
T read(const uint8_t *&data, size_t &size)
Definition serialized.h:58
Definition serializer.h:15
std::shared_ptr< AbstractSerializedSection > PartialSerialization
Definition serializer.h:142
STL namespace.
Definition serializer.h:136
virtual size_t size() const =0
virtual const uint8_t * data() const =0
virtual ~AbstractSerializedSection()=default
Definition serializer.h:27
const size_t size
Definition serializer.h:29
const uint8_t * data
Definition serializer.h:28
Definition serializer.h:146
const T t
Definition serializer.h:147
const uint8_t * data() const override
Definition serializer.h:151
size_t size() const override
Definition serializer.h:156
CopiedSection(const T &t_)
Definition serializer.h:149
Definition serializer.h:181
const size_t s
Definition serializer.h:183
MemoryRegionSection(const uint8_t *data_, size_t size_)
Definition serializer.h:185
const uint8_t *const d
Definition serializer.h:182
const uint8_t * data() const override
Definition serializer.h:188
size_t size() const override
Definition serializer.h:193
Definition serializer.h:164
const T & t
Definition serializer.h:165
RawSection(const T &t_)
Definition serializer.h:167
const uint8_t * data() const override
Definition serializer.h:169
size_t size() const override
Definition serializer.h:174
std::remove_cvref_t< typename std::tuple_element_t< I, Tup > > CanonTarget
Definition serializer.h:76
static constexpr bool value
Definition serializer.h:95
std::remove_cvref_t< T > CanonArgument
Definition serializer.h:77
static constexpr bool value
Definition serializer.h:110
static constexpr bool value
Definition serializer.h:123
static constexpr bool value
Definition serializer.h:66
Definition serializer.h:60
static constexpr size_t TupSize
Definition serializer.h:61
static constexpr bool close_enough_v
Definition serializer.h:127
static constexpr bool correct_size_v
Definition serializer.h:70
Definition serializer.h:132