roo_transport
API Documentation for roo_transport
Loading...
Searching...
No Matches
serialization.h
Go to the documentation of this file.
1#pragma once
2
3#include <memory>
4#include <vector>
5
6#include "roo_backport.h"
7#include "roo_backport/byte.h"
8#include "roo_backport/string_view.h"
9#include "roo_io/data/read.h"
10#include "roo_io/data/write.h"
11#include "roo_io/memory/load.h"
12#include "roo_io/memory/store.h"
14
15namespace roo_transport {
16
17struct Void {};
18
19template <typename T>
21
22template <typename T>
24
26 RpcStatus status() const { return kOk; }
27 const roo::byte* data() const { return nullptr; }
28 size_t size() const { return 0; }
29};
30
31/// Serialized holder for small fixed-size payloads.
32template <size_t N>
34 public:
35 StaticSerialized() = default;
36
37 RpcStatus status() const { return kOk; }
38 const roo::byte* data() const { return data_; }
39 size_t size() const { return N; }
40
41 roo::byte* data() { return data_; }
42
43 private:
44 roo::byte data_[N];
45};
46
47/// Serialized holder for variable-sized payloads stored on heap.
49 public:
50 SimpleSerialized() : status_(kOk), data_(nullptr), size_(0) {}
51
53 : status_(error), data_(nullptr), size_(0) {}
54
55 SimpleSerialized(std::unique_ptr<roo::byte[]> data, size_t size)
56 : status_(kOk), data_(std::move(data)), size_(size) {}
57
58 RpcStatus status() const { return status_; }
59 const roo::byte* data() const { return data_.get(); }
60 size_t size() const { return size_; }
61
62 private:
63 RpcStatus status_;
64 std::unique_ptr<roo::byte[]> data_;
65 size_t size_;
66};
67
68/// Mutable serialized buffer supporting append and random-position writes.
70 public:
71 DynamicSerialized() : status_(kOk), data_(), pos_(0) {}
72
73 // DynamicSerialized(RpcStatus error)
74 // : status_(error), data_() {}
75
76 // DynamicSerialized(std::unique_ptr<roo::byte[]> data, size_t size)
77 // : status_(kOk), data_(std::move(data)), size_(size) {}
78
80 status_ = status;
81 data_.clear();
82 pos_ = 0;
83 }
84
85 RpcStatus status() const { return status_; }
86
87 const roo::byte* data() const {
88 return data_.empty() ? nullptr : &*data_.begin();
89 }
90
91 size_t pos() const { return pos_; }
92 size_t size() const { return data_.size(); }
93
94 bool eos() const { return pos_ >= data_.size(); }
95
96 /// Iterator contract: writes one byte at current position and advances.
97 void write(roo::byte b) {
98 if (eos()) {
99 if (pos_ > data_.size()) {
100 data_.insert(data_.end(), pos_ - data_.size(), roo::byte{0});
101 }
102 data_.push_back(b);
103 } else {
104 data_[pos_] = b;
105 }
106 pos_++;
107 }
108
109 size_t write(const roo::byte* buf, size_t count) {
110 if (pos_ > data_.size()) {
111 data_.insert(data_.end(), pos_ - data_.size(), roo::byte{0});
112 }
113 size_t copy_over = data_.size() - pos_;
114 if (copy_over > count) {
116 }
117 std::copy(buf, buf + copy_over, data_.begin() + pos_);
118 pos_ += copy_over;
119 buf += copy_over;
120 size_t remaining = count - copy_over;
121 if (remaining == 0) {
122 return copy_over;
123 }
124 data_.insert(data_.end(), buf, buf + remaining);
125 pos_ += remaining;
126 return count;
127 }
128
129 void seek(size_t position) { pos_ = position; }
130
131 private:
132 RpcStatus status_;
133 std::vector<roo::byte> data_;
134 size_t pos_;
135};
136
137/// Default bridge implementing `SerializeInto()` via `serialize()`.
138template <typename T, typename Itr, typename S = Serializer<T>, typename = void>
140 void operator()(const T& val, Itr& output) const {
142 auto serialized = serializer.serialize(val);
143 output.write(serialized.data(), serialized.size());
144 }
145};
146
147/// Specialization using `Serializer<T>::serializeInto()` when available.
148template <typename T, typename Itr>
150 decltype(std::declval<Serializer<T>>().serializeInto(
151 std::declval<const T&>(),
152 std::declval<Itr&>()),
153 void())> {
154 void operator()(const T& val, Itr& output) const {
156 serializer.serializeInto(val, output);
157 }
158};
159
160template <typename T, typename Itr>
164
165/// Simple serializers/deserializers for basic types are provided below.
166
167/// `Void`.
168
169template <>
171 NullSerialized serialize(const Void&) const { return NullSerialized(); }
172};
173
174template <>
176 RpcStatus deserialize(const roo::byte* data, size_t len, Void& result) const {
177 if (len != 0) {
179 }
180 return roo_transport::kOk;
181 }
182};
183
184/// `bool`.
185
186template <>
190 roo_io::StoreU8(val, result.data());
191 return result;
192 }
193};
194
195template <>
197 RpcStatus deserialize(const roo::byte* data, size_t len, bool& result) const {
198 if (len != 1) {
200 }
201 uint8_t val = roo_io::LoadU8(data);
202 if (val > 1) {
204 }
205 result = (val != 0);
206 return roo_transport::kOk;
207 }
208};
209
210/// `int8_t`.
211
212template <>
216 roo_io::StoreS8(val, result.data());
217 return result;
218 }
219};
220
221template <>
223 RpcStatus deserialize(const roo::byte* data, size_t len,
224 int8_t& result) const {
225 if (len != 1) {
227 }
228 result = roo_io::LoadS8(data);
229 return roo_transport::kOk;
230 }
231};
232
233/// `uint8_t`.
234
235template <>
239 roo_io::StoreU8(val, result.data());
240 return result;
241 }
242};
243
244template <>
246 RpcStatus deserialize(const roo::byte* data, size_t len,
247 uint8_t& result) const {
248 if (len != 1) {
250 }
251 result = roo_io::LoadU8(data);
252 return roo_transport::kOk;
253 }
254};
255
256/// `int16_t`.
257
258template <>
262 roo_io::StoreBeS16(val, result.data());
263 return result;
264 }
265};
266
267template <>
269 RpcStatus deserialize(const roo::byte* data, size_t len,
270 int16_t& result) const {
271 if (len != 2) {
273 }
274 result = roo_io::LoadBeS16(data);
275 return roo_transport::kOk;
276 }
277};
278
279/// `uint16_t`.
280
281template <>
285 roo_io::StoreBeU16(val, result.data());
286 return result;
287 }
288};
289
290template <>
292 RpcStatus deserialize(const roo::byte* data, size_t len,
293 uint16_t& result) const {
294 if (len != 2) {
296 }
297 result = roo_io::LoadBeU16(data);
298 return roo_transport::kOk;
299 }
300};
301
302/// `int32_t`.
303
304template <>
308 roo_io::StoreBeS32(val, result.data());
309 return result;
310 }
311};
312
313template <>
315 RpcStatus deserialize(const roo::byte* data, size_t len,
316 int32_t& result) const {
317 if (len != 4) {
319 }
320 result = roo_io::LoadBeS32(data);
321 return roo_transport::kOk;
322 }
323};
324
325/// `uint32_t`.
326
327template <>
331 roo_io::StoreBeU32(val, result.data());
332 return result;
333 }
334};
335
336template <>
338 RpcStatus deserialize(const roo::byte* data, size_t len,
339 uint32_t& result) const {
340 if (len != 4) {
342 }
343 result = roo_io::LoadBeU32(data);
344 return roo_transport::kOk;
345 }
346};
347
348/// `int64_t`.
349
350template <>
354 roo_io::StoreBeS64(val, result.data());
355 return result;
356 }
357};
358
359template <>
361 RpcStatus deserialize(const roo::byte* data, size_t len,
362 int64_t& result) const {
363 if (len != 8) {
365 }
366 result = roo_io::LoadBeS64(data);
367 return roo_transport::kOk;
368 }
369};
370
371/// `uint64_t`.
372
373template <>
377 roo_io::StoreBeU64(val, result.data());
378 return result;
379 }
380};
381
382template <>
384 RpcStatus deserialize(const roo::byte* data, size_t len,
385 uint64_t& result) const {
386 if (len != 8) {
388 }
389 result = roo_io::LoadBeU64(data);
390 return roo_transport::kOk;
391 }
392};
393
394/// `roo::string_view`.
395
397 public:
398 SerializedByteArrayAdapter(const roo::byte* data, size_t size)
399 : data_(data), size_(size) {}
400
401 RpcStatus status() const { return kOk; }
402 const roo::byte* data() const { return data_; }
403 size_t size() const { return size_; }
404
405 private:
406 const roo::byte* data_;
407 size_t size_;
408};
409
410template <>
412 SerializedByteArrayAdapter serialize(roo::string_view val) const {
414 reinterpret_cast<const roo::byte*>(val.data()), val.size());
415 }
416};
417
418template <>
420 RpcStatus deserialize(const roo::byte* data, size_t len,
421 roo::string_view& result) const {
422 result = roo::string_view(reinterpret_cast<const char*>(data), len);
423 return roo_transport::kOk;
424 }
425};
426
427/// Serializes nested member with 16-bit big-endian length prefix.
428template <typename T, typename RandomItr>
430 size_t begin = result.pos();
431 result.seek(begin + 2);
433 if (result.status() != kOk) return;
434 size_t end = result.pos();
435 size_t len = end - (begin + 2);
436 if (len > 65535) {
438 return;
439 }
440 result.seek(begin);
441 roo_io::WriteBeU16(result, (uint16_t)len);
442 result.seek(end);
443}
444
445template <typename T>
446constexpr RpcStatus DeserializeMember(const roo::byte*& data, size_t& len,
447 T& result) {
448 if (len < 2) {
450 }
451 uint16_t member_len = roo_io::LoadBeU16(data);
452 if (len < 2 + member_len) {
454 }
455 data += 2;
456 len -= 2;
458 RpcStatus status = d.deserialize(data, member_len, result);
459 if (status != kOk) {
460 return status;
461 }
462 data += member_len;
463 len -= member_len;
464 return kOk;
465}
466
467/// `std::pair<T1, T2>`.
468
469template <typename T1, typename T2>
470struct Serializer<std::pair<T1, T2>> {
471 template <typename RandomItr>
472 void serializeInto(const std::pair<T1, T2>& val, RandomItr& result) const {
474 if (result.status() != kOk) return;
476 }
477
478 DynamicSerialized serialize(const std::pair<T1, T2>& val) const {
480 serializeInto(val, result);
481 return result;
482 }
483};
484
485template <typename T1, typename T2>
486struct Deserializer<std::pair<T1, T2>> {
487 RpcStatus deserialize(const roo::byte* data, size_t len,
488 std::pair<T1, T2>& result) const {
489 RpcStatus status;
490 status = DeserializeMember(data, len, result.first);
491 if (status != roo_transport::kOk) {
492 return status;
493 }
494 status = DeserializeMember(data, len, result.second);
495 if (status != roo_transport::kOk) {
496 return status;
497 }
498 if (len != 0) {
500 }
501 return roo_transport::kOk;
502 }
503};
504
505/// `std::tuple<Types...>`.
506
507template <size_t index, typename RandomItr, typename... Types>
508constexpr void SerializeTupleRecursive(const std::tuple<Types...>& t,
509 RandomItr& result) {
510 SerializeMemberInto(std::get<index>(t), result);
511 if (result.status() != kOk) return;
512 if constexpr (index < sizeof...(Types) - 1) {
514 }
515}
516
517template <typename... Types>
518struct Serializer<std::tuple<Types...>> {
519 template <typename RandomItr>
520 constexpr void serializeInto(const std::tuple<Types...>& val,
521 RandomItr& result) const {
523 }
524
525 DynamicSerialized serialize(const std::tuple<Types...>& val) const {
528 return result;
529 }
530};
531
532template <size_t index, typename... Types>
533constexpr RpcStatus DeserializeTupleRecursive(std::tuple<Types...>& t,
534 const roo::byte* data,
535 size_t len) {
536 RpcStatus status = DeserializeMember(data, len, std::get<index>(t));
537 if (status != kOk) {
538 return status;
539 }
540 if constexpr (index < sizeof...(Types) - 1) {
542 }
543 if (len != 0) {
544 return kInvalidArgument;
545 }
546 return kOk;
547}
548
549template <typename... Types>
550struct Deserializer<std::tuple<Types...>> {
551 RpcStatus deserialize(const roo::byte* data, size_t len,
552 std::tuple<Types...>& result) const {
554 }
555};
556
557} // namespace roo_transport
Mutable serialized buffer supporting append and random-position writes.
void write(roo::byte b)
Iterator contract: writes one byte at current position and advances.
const roo::byte * data() const
void fail(RpcStatus status)
size_t write(const roo::byte *buf, size_t count)
SerializedByteArrayAdapter(const roo::byte *data, size_t size)
Serialized holder for variable-sized payloads stored on heap.
const roo::byte * data() const
SimpleSerialized(std::unique_ptr< roo::byte[]> data, size_t size)
Serialized holder for small fixed-size payloads.
const roo::byte * data() const
@ kInvalidArgument
Definition status.h:26
constexpr void SerializeTupleRecursive(const std::tuple< Types... > &t, RandomItr &result)
std::tuple<Types...>.
constexpr RpcStatus DeserializeTupleRecursive(std::tuple< Types... > &t, const roo::byte *data, size_t len)
constexpr RpcStatus DeserializeMember(const roo::byte *&data, size_t &len, T &result)
void SerializeInto(const T &val, Itr &output)
void SerializeMemberInto(const T &val, RandomItr &result)
Serializes nested member with 16-bit big-endian length prefix.
RpcStatus deserialize(const roo::byte *data, size_t len, Void &result) const
RpcStatus deserialize(const roo::byte *data, size_t len, bool &result) const
RpcStatus deserialize(const roo::byte *data, size_t len, int16_t &result) const
RpcStatus deserialize(const roo::byte *data, size_t len, int32_t &result) const
RpcStatus deserialize(const roo::byte *data, size_t len, int64_t &result) const
RpcStatus deserialize(const roo::byte *data, size_t len, int8_t &result) const
RpcStatus deserialize(const roo::byte *data, size_t len, roo::string_view &result) const
RpcStatus deserialize(const roo::byte *data, size_t len, std::pair< T1, T2 > &result) const
RpcStatus deserialize(const roo::byte *data, size_t len, std::tuple< Types... > &result) const
RpcStatus deserialize(const roo::byte *data, size_t len, uint16_t &result) const
RpcStatus deserialize(const roo::byte *data, size_t len, uint32_t &result) const
RpcStatus deserialize(const roo::byte *data, size_t len, uint64_t &result) const
RpcStatus deserialize(const roo::byte *data, size_t len, uint8_t &result) const
Default bridge implementing SerializeInto() via serialize().
void operator()(const T &val, Itr &output) const
const roo::byte * data() const
NullSerialized serialize(const Void &) const
StaticSerialized< 1 > serialize(bool val) const
StaticSerialized< 2 > serialize(int16_t val) const
StaticSerialized< 4 > serialize(int32_t val) const
StaticSerialized< 8 > serialize(int64_t val) const
StaticSerialized< 1 > serialize(int8_t val) const
SerializedByteArrayAdapter serialize(roo::string_view val) const
void serializeInto(const std::pair< T1, T2 > &val, RandomItr &result) const
DynamicSerialized serialize(const std::pair< T1, T2 > &val) const
DynamicSerialized serialize(const std::tuple< Types... > &val) const
constexpr void serializeInto(const std::tuple< Types... > &val, RandomItr &result) const
StaticSerialized< 2 > serialize(uint16_t val) const
StaticSerialized< 4 > serialize(uint32_t val) const
StaticSerialized< 8 > serialize(uint64_t val) const
StaticSerialized< 1 > serialize(uint8_t val) const