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
32 namespace details
33 {
36 template <size_t I = 0, typename F, typename... Ts>
37 static auto tuple_apply(const std::tuple<Ts...>& t, const F& f)
38 {
39 if constexpr (sizeof...(Ts) == 1)
40 {
41 return std::make_tuple();
42 }
43 else if constexpr (I == sizeof...(Ts) - 1)
44 {
45 return f(std::get<I>(t));
46 }
47 else
48 {
49 return std::tuple_cat(f(std::get<I>(t)), tuple_apply<I + 1>(t, f));
50 }
51 }
52
53 template <typename Tup>
55 {
56 static constexpr size_t TupSize = std::tuple_size_v<Tup>;
57
58 template <typename... Ts>
60 {
61 static constexpr bool value = TupSize == sizeof...(Ts);
62 };
63
64 template <typename... Ts>
65 static constexpr bool correct_size_v = correct_size<Ts...>::value;
66
67 template <size_t I, typename T>
69 {
71 std::remove_cvref_t<typename std::tuple_element_t<I, Tup>>;
72 using CanonArgument = std::remove_cvref_t<T>;
73
74 // This determines what types a Serializer will accept as arguments to
75 // serialize(...), relative to the declared param types.
76 // The main feature is the removal of const, volatile, and references
77 // from the type so that a Serializer<int> will accept an argument of
78 // type const int&.
79 // Additionally, this will accept ByteRange arguments for parameters
80 // declared as std::vector<uint8_t> and vice versa - when serializing we
81 // can copy bytes from either in the same way, but there is a
82 // distinction in the deserialized type of whether we are copying (to a
83 // byte vector) or referring to an existing byte range. It may be
84 // possible to generalise this further and replace with
85 // std::is_constructible, but these restrictions are sufficient for the
86 // current uses.
87 // Additionally again, this will accept an array-like of ByteRanges for
88 // a single ByteRange parameter. These will be serialised in-order, and
89 // produce a single ByteRange in deserialisation.
90 static constexpr bool value =
91 std::is_same_v<CanonTarget, CanonArgument> ||
92 (std::is_same_v<CanonTarget, std::vector<uint8_t>> &&
93 std::is_same_v<CanonArgument, ByteRange>) ||
94 (std::is_same_v<CanonTarget, ByteRange> &&
95 std::is_same_v<CanonArgument, std::vector<uint8_t>>) ||
96 (std::is_same_v<CanonTarget, ByteRange> &&
97 (std::is_array_v<CanonArgument> &&
98 std::is_same_v<std::remove_extent_t<CanonArgument>, ByteRange>));
99 };
100
101 // Only reached when Ts is empty
102 template <size_t I, typename... Ts>
104 {
105 static constexpr bool value = I == TupSize;
106 };
107
108 template <size_t I, typename T, typename... Ts>
109 struct close_enough_from<I, T, Ts...>
110 {
111 static constexpr bool value = close_enough_at<I, T>::value &&
112 close_enough_from<I + 1, Ts...>::value;
113 };
114
115 template <typename... Ts>
117 {
118 static constexpr bool value = close_enough_from<0, Ts...>::value;
119 };
120
121 template <typename... Ts>
122 static constexpr bool close_enough_v = close_enough<Ts...>::value;
123 };
124
125 template <typename... Ts>
126 struct TypeMatcher : public TupMatcher<std::tuple<Ts...>>
127 {};
128 }
129
131 {
132 virtual ~AbstractSerializedSection() = default;
133 virtual const uint8_t* data() const = 0;
134 virtual size_t size() const = 0;
135 };
136
137 using PartialSerialization = std::shared_ptr<AbstractSerializedSection>;
138
139 template <typename T>
141 {
142 const T t;
143
144 CopiedSection(const T& t_) : t(t_) {}
145
146 virtual const uint8_t* data() const override
147 {
148 return reinterpret_cast<const uint8_t*>(&t);
149 }
150
151 virtual size_t size() const override
152 {
153 return sizeof(T);
154 }
155 };
156
157 template <typename T>
159 {
160 const T& t;
161
162 RawSection(const T& t_) : t(t_) {}
163
164 virtual const uint8_t* data() const override
165 {
166 return reinterpret_cast<const uint8_t*>(&t);
167 }
168
169 virtual size_t size() const override
170 {
171 return sizeof(T);
172 }
173 };
174
176 {
177 const uint8_t* const d;
178 const size_t s;
179
180 MemoryRegionSection(const uint8_t* data_, size_t size_) : d(data_), s(size_)
181 {}
182
183 virtual const uint8_t* data() const override
184 {
185 return d;
186 }
187
188 virtual size_t size() const override
189 {
190 return s;
191 }
192 };
193
195 {
196 public:
198 template <typename... Ts>
199 static std::tuple<> serialize(const Ts&... ts)
200 {
201 static_assert(
202 sizeof...(ts) == 0,
203 "EmptySerializer was given message payload to serialize - can only "
204 "serialize empty "
205 "messages");
206 return std::make_tuple();
207 }
208
209 template <typename... Ts>
210 static std::tuple<> deserialize(const uint8_t*, size_t size)
211 {
212 if constexpr (sizeof...(Ts) == 0)
213 {
214 if (size > 0)
215 throw std::logic_error(
216 "EmptySerializer asked to deserialize buffer of size " +
217 std::to_string(size) + ", should be empty");
218 }
219 return std::make_tuple();
220 }
221 };
222
224 {
225 template <size_t N, size_t... Is>
226 static auto serialize_byte_range_with_index_sequence(
227 const ByteRange (&brs)[N], std::index_sequence<Is...>)
228 {
229 return std::make_tuple(
230 std::make_shared<MemoryRegionSection>(brs[Is].data, brs[Is].size)...);
231 }
232
236 static auto serialize_value(const ByteRange& br)
237 {
238 auto cs = std::make_shared<CopiedSection<size_t>>(br.size);
239 auto bfs = std::make_shared<MemoryRegionSection>(br.data, br.size);
240 return std::tuple_cat(std::make_tuple(cs), std::make_tuple(bfs));
241 }
242
245 template <size_t N>
246 static auto serialize_value(const ByteRange (&brs)[N])
247 {
248 return serialize_byte_range_with_index_sequence(
249 brs, std::make_index_sequence<N>{});
250 }
251
253 static auto serialize_value(const std::vector<uint8_t>& vec)
254 {
255 auto cs = std::make_shared<CopiedSection<size_t>>(vec.size());
256 auto bfs = std::make_shared<MemoryRegionSection>(vec.data(), vec.size());
257 return std::tuple_cat(std::make_tuple(cs), std::make_tuple(bfs));
258 }
259
263 static auto serialize_value(std::span<uint8_t> s)
264 {
265 auto csd = std::make_shared<CopiedSection<uintptr_t>>(
266 reinterpret_cast<std::uintptr_t>(s.data()));
267 auto css = std::make_shared<CopiedSection<size_t>>(s.size());
268 return std::tuple_cat(std::make_tuple(csd), std::make_tuple(css));
269 }
270
272 static auto serialize_value(const std::string& s)
273 {
274 auto cs = std::make_shared<CopiedSection<size_t>>(s.size());
275 auto bfs = std::make_shared<MemoryRegionSection>(
276 reinterpret_cast<const uint8_t*>(s.data()), s.size());
277 return std::tuple_cat(std::make_tuple(cs), std::make_tuple(bfs));
278 }
279
281 template <
282 typename T,
283 std::enable_if_t<
284 std::is_integral<T>::value || std::is_enum<T>::value,
285 bool> = true>
286 static auto serialize_value(const T& t)
287 {
288 auto rs = std::make_shared<RawSection<T>>(t);
289 return std::make_tuple(rs);
290 }
292
297 static auto serialize_value_final(const ByteRange& br)
298 {
299 auto bfs = std::make_shared<MemoryRegionSection>(br.data, br.size);
300 return std::make_tuple(bfs);
301 }
302
305 static auto serialize_value_final(const std::vector<uint8_t>& vec)
306 {
307 auto bfs = std::make_shared<MemoryRegionSection>(vec.data(), vec.size());
308 return std::make_tuple(bfs);
309 }
310
312 template <typename T>
313 static auto serialize_value_final(const T& t)
314 {
315 return serialize_value(t);
316 }
318
320 template <typename T>
321 struct Tag
322 {
323 using type = T;
324 };
325
329 static ByteRange deserialize_value(
330 const uint8_t*& data, size_t& size, const Tag<ByteRange>&)
331 {
332 const auto prefixed_size = serialized::read<size_t>(data, size);
333 ByteRange br{data, prefixed_size};
334 serialized::skip(data, size, prefixed_size);
335 return br;
336 }
337
339 static std::vector<uint8_t> deserialize_value(
340 const uint8_t*& data, size_t& size, const Tag<std::vector<uint8_t>>&)
341 {
342 const auto prefixed_size = serialized::read<size_t>(data, size);
343 return serialized::read(data, size, prefixed_size);
344 }
345
347 static std::span<uint8_t> deserialize_value(
348 const uint8_t*& data, size_t& size, const Tag<std::span<uint8_t>>&)
349 {
350 const auto ptr = serialized::read<uintptr_t>(data, size);
351 const auto s = serialized::read<size_t>(data, size);
352 return {reinterpret_cast<uint8_t*>(ptr), s};
353 }
354
356 static std::string deserialize_value(
357 const uint8_t*& data, size_t& size, const Tag<std::string>&)
358 {
359 return serialized::read<std::string>(data, size);
360 }
361
363 template <
364 typename T,
365 std::enable_if_t<
366 std::is_integral<T>::value || std::is_enum<T>::value,
367 bool> = true>
368 static T deserialize_value(
369 const uint8_t*& data, size_t& size, const Tag<T>&)
370 {
371 return serialized::read<T>(data, size);
372 }
374
378 static auto deserialize_value_final(
379 const uint8_t*& data, size_t& size, const Tag<ByteRange>&)
380 {
381 ByteRange br{data, size};
382 serialized::skip(data, size, size);
383 return br;
384 }
385
387 static auto deserialize_value_final(
388 const uint8_t*& data, size_t& size, const Tag<std::vector<uint8_t>>&)
389 {
390 return serialized::read(data, size, size);
391 }
392
394 template <typename T>
395 static T deserialize_value_final(
396 const uint8_t*& data, size_t& size, const Tag<T>& tag)
397 {
398 return deserialize_value(data, size, tag);
399 }
401
402 template <typename T, typename... Ts>
403 static auto deserialize_impl(const uint8_t* data, size_t size)
404 {
405 using StrippedT = std::remove_cvref_t<T>;
406
407 if constexpr (sizeof...(Ts) == 0)
408 {
409 return std::make_tuple(
410 deserialize_value_final(data, size, Tag<StrippedT>{}));
411 }
412 else
413 {
414 const auto next =
415 std::make_tuple(deserialize_value(data, size, Tag<StrippedT>{}));
416 return std::tuple_cat(next, deserialize_impl<Ts...>(data, size));
417 }
418 }
419
420 public:
421 // Can also serialize empty messages
423
426 template <typename T, typename... Ts>
427 static auto serialize(T&& t, Ts&&... ts)
428 {
429 if constexpr (sizeof...(Ts) == 0)
430 {
431 return serialize_value_final(std::forward<T>(t));
432 }
433 else
434 {
435 const auto next = serialize_value(std::forward<T>(t));
436 return std::tuple_cat(next, serialize(std::forward<Ts>(ts)...));
437 }
438 }
439
440 template <typename... Ts>
441 static auto deserialize(const uint8_t* data, size_t size)
442 {
443 if constexpr (sizeof...(Ts) == 0)
444 {
445 return EmptySerializer::deserialize(data, size);
446 }
447 else
448 {
449 return deserialize_impl<Ts...>(data, size);
450 }
451 }
452 };
453
454 // Serializes a list of exactly these argument types, and nothing else
455 template <typename... Us>
457 {
458 using Matcher = details::TypeMatcher<Us...>;
459
460 public:
461 template <typename... Ts>
462 static auto serialize(Ts&&... ts)
463 {
464 static_assert(
465 Matcher::template correct_size_v<Ts...>,
466 "Incorrect number of arguments for PreciseSerializer");
467 static_assert(
468 Matcher::template close_enough_v<Ts...>,
469 "Incorrect type of arguments for PreciseSerializer");
470
471 return CommonSerializer::serialize(std::forward<Ts>(ts)...);
472 }
473
474 template <typename... Ts>
475 static auto deserialize(const uint8_t* data, size_t size)
476 {
477 static_assert(
478 Matcher::template correct_size_v<Ts...>,
479 "Incorrect number of results for PreciseSerializer");
480 static_assert(
481 Matcher::template close_enough_v<Ts...>,
482 "Incorrect type of results for PreciseSerializer");
483
484 return CommonSerializer::deserialize<Us...>(data, size);
485 }
486
487 static auto deserialize(const uint8_t* data, size_t size)
488 {
489 return CommonSerializer::deserialize<Us...>(data, size);
490 }
491 };
492
493 template <typename>
495
496 // Specializes a specific tuple-type only. Removes ref and const when
497 // comparing types, ie tuple<int, const float&> will be accepted by
498 // TupleSerializers specialized at tuple<int, float>, tuple<const int&, const
499 // float&> etc
500 template <typename... Us>
501 class TupleSerializer<std::tuple<Us...>> : private CommonSerializer
502 {
503 using Tup = std::tuple<Us...>;
505
506 public:
507 template <typename... Ts>
508 static auto serialize(std::tuple<Ts...>&& t)
509 {
510 static_assert(
511 Matcher::template correct_size_v<Ts...>,
512 "Incorrect tuple size for TupleSerializer");
513 static_assert(
514 Matcher::template close_enough_v<Ts...>,
515 "Incorrect tuple type for TupleSerializer");
516
517 return details::tuple_apply(
518 t, [](const auto& e) { return CommonSerializer::serialize(e); });
519 }
520
521 // Takes variadic arguments list, they don't need to be packed in tuple
522 template <typename... Ts>
523 static auto serialize(Ts&&... ts)
524 {
525 static_assert(
526 Matcher::template correct_size_v<Ts...>,
527 "Incorrect number of args for unpacked TupleSerializer");
528 static_assert(
529 Matcher::template close_enough_v<Ts...>,
530 "Incorrect arg types for unpacked TupleSerializer");
531
532 return CommonSerializer::serialize(std::forward<Ts>(ts)...);
533 }
534
535 template <typename... Ts>
536 static auto deserialize(const uint8_t* data, size_t size)
537 {
538 static_assert(
539 Matcher::template correct_size_v<Ts...>,
540 "Incorrect number of results for TupleSerializer");
541 static_assert(
542 Matcher::template close_enough_v<Ts...>,
543 "Incorrect type of results for TupleSerializer");
544
545 return CommonSerializer::deserialize<Ts...>(data, size);
546 }
547
548 static auto deserialize(const uint8_t* data, size_t size)
549 {
550 return CommonSerializer::deserialize<Us...>(data, size);
551 }
552 };
553} // namespace serializer
Definition serializer.h:224
static auto deserialize(const uint8_t *data, size_t size)
Definition serializer.h:441
static auto serialize(T &&t, Ts &&... ts)
Definition serializer.h:427
Definition serializer.h:195
static std::tuple deserialize(const uint8_t *, size_t size)
Definition serializer.h:210
static std::tuple serialize(const Ts &... ts)
Can serialize empty messages, but nothing else.
Definition serializer.h:199
Definition serializer.h:457
static auto deserialize(const uint8_t *data, size_t size)
Definition serializer.h:487
static auto deserialize(const uint8_t *data, size_t size)
Definition serializer.h:475
static auto serialize(Ts &&... ts)
Definition serializer.h:462
static auto deserialize(const uint8_t *data, size_t size)
Definition serializer.h:548
static auto serialize(Ts &&... ts)
Definition serializer.h:523
static auto serialize(std::tuple< Ts... > &&t)
Definition serializer.h:508
static auto deserialize(const uint8_t *data, size_t size)
Definition serializer.h:536
Definition serializer.h:494
void skip(const uint8_t *&data, size_t &size, size_t skip)
Definition serialized.h:166
T read(const uint8_t *&data, size_t &size)
Definition serialized.h:59
Definition serializer.h:15
std::shared_ptr< AbstractSerializedSection > PartialSerialization
Definition serializer.h:137
STL namespace.
Definition serializer.h:131
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:141
const T t
Definition serializer.h:142
CopiedSection(const T &t_)
Definition serializer.h:144
virtual size_t size() const override
Definition serializer.h:151
virtual const uint8_t * data() const override
Definition serializer.h:146
Definition serializer.h:176
const size_t s
Definition serializer.h:178
MemoryRegionSection(const uint8_t *data_, size_t size_)
Definition serializer.h:180
const uint8_t *const d
Definition serializer.h:177
virtual const uint8_t * data() const override
Definition serializer.h:183
virtual size_t size() const override
Definition serializer.h:188
Definition serializer.h:159
const T & t
Definition serializer.h:160
virtual const uint8_t * data() const override
Definition serializer.h:164
RawSection(const T &t_)
Definition serializer.h:162
virtual size_t size() const override
Definition serializer.h:169
std::remove_cvref_t< typename std::tuple_element_t< I, Tup > > CanonTarget
Definition serializer.h:71
static constexpr bool value
Definition serializer.h:90
std::remove_cvref_t< T > CanonArgument
Definition serializer.h:72
static constexpr bool value
Definition serializer.h:105
static constexpr bool value
Definition serializer.h:118
static constexpr bool value
Definition serializer.h:61
Definition serializer.h:55
static constexpr size_t TupSize
Definition serializer.h:56
static constexpr bool close_enough_v
Definition serializer.h:122
static constexpr bool correct_size_v
Definition serializer.h:65
Definition serializer.h:127