1//===--- simple_packed_serialization.h - simple serialization ---*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file is a part of the ORC runtime support library.
10//
11// The behavior of the utilities in this header must be synchronized with the
12// behavior of the utilities in
13// llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h.
14//
15// The Simple Packed Serialization (SPS) utilities are used to generate
16// argument and return buffers for wrapper functions using the following
17// serialization scheme:
18//
19// Primitives:
20// bool, char, int8_t, uint8_t -- Two's complement 8-bit (0=false, 1=true)
21// int16_t, uint16_t -- Two's complement 16-bit little endian
22// int32_t, uint32_t -- Two's complement 32-bit little endian
23// int64_t, int64_t -- Two's complement 64-bit little endian
24//
25// Sequence<T>:
26// Serialized as the sequence length (as a uint64_t) followed by the
27// serialization of each of the elements without padding.
28//
29// Tuple<T1, ..., TN>:
30// Serialized as each of the element types from T1 to TN without padding.
31//
32//===----------------------------------------------------------------------===//
33
34#ifndef ORC_RT_SIMPLE_PACKED_SERIALIZATION_H
35#define ORC_RT_SIMPLE_PACKED_SERIALIZATION_H
36
37#include "adt.h"
38#include "endianness.h"
39#include "error.h"
40#include "stl_extras.h"
41
42#include <optional>
43#include <string>
44#include <string_view>
45#include <tuple>
46#include <type_traits>
47#include <unordered_map>
48#include <utility>
49#include <vector>
50
51namespace __orc_rt {
52
53/// Output char buffer with overflow check.
54class SPSOutputBuffer {
55public:
56 SPSOutputBuffer(char *Buffer, size_t Remaining)
57 : Buffer(Buffer), Remaining(Remaining) {}
58 bool write(const char *Data, size_t Size) {
59 if (Size > Remaining)
60 return false;
61 memcpy(dest: Buffer, src: Data, n: Size);
62 Buffer += Size;
63 Remaining -= Size;
64 return true;
65 }
66
67private:
68 char *Buffer = nullptr;
69 size_t Remaining = 0;
70};
71
72/// Input char buffer with underflow check.
73class SPSInputBuffer {
74public:
75 SPSInputBuffer() = default;
76 SPSInputBuffer(const char *Buffer, size_t Remaining)
77 : Buffer(Buffer), Remaining(Remaining) {}
78 bool read(char *Data, size_t Size) {
79 if (Size > Remaining)
80 return false;
81 memcpy(dest: Data, src: Buffer, n: Size);
82 Buffer += Size;
83 Remaining -= Size;
84 return true;
85 }
86
87 const char *data() const { return Buffer; }
88 bool skip(size_t Size) {
89 if (Size > Remaining)
90 return false;
91 Buffer += Size;
92 Remaining -= Size;
93 return true;
94 }
95
96private:
97 const char *Buffer = nullptr;
98 size_t Remaining = 0;
99};
100
101/// Specialize to describe how to serialize/deserialize to/from the given
102/// concrete type.
103template <typename SPSTagT, typename ConcreteT, typename _ = void>
104class SPSSerializationTraits;
105
106/// A utility class for serializing to a blob from a variadic list.
107template <typename... ArgTs> class SPSArgList;
108
109// Empty list specialization for SPSArgList.
110template <> class SPSArgList<> {
111public:
112 static size_t size() { return 0; }
113
114 static bool serialize(SPSOutputBuffer &OB) { return true; }
115 static bool deserialize(SPSInputBuffer &IB) { return true; }
116};
117
118// Non-empty list specialization for SPSArgList.
119template <typename SPSTagT, typename... SPSTagTs>
120class SPSArgList<SPSTagT, SPSTagTs...> {
121public:
122 template <typename ArgT, typename... ArgTs>
123 static size_t size(const ArgT &Arg, const ArgTs &...Args) {
124 return SPSSerializationTraits<SPSTagT, ArgT>::size(Arg) +
125 SPSArgList<SPSTagTs...>::size(Args...);
126 }
127
128 template <typename ArgT, typename... ArgTs>
129 static bool serialize(SPSOutputBuffer &OB, const ArgT &Arg,
130 const ArgTs &...Args) {
131 return SPSSerializationTraits<SPSTagT, ArgT>::serialize(OB, Arg) &&
132 SPSArgList<SPSTagTs...>::serialize(OB, Args...);
133 }
134
135 template <typename ArgT, typename... ArgTs>
136 static bool deserialize(SPSInputBuffer &IB, ArgT &Arg, ArgTs &...Args) {
137 return SPSSerializationTraits<SPSTagT, ArgT>::deserialize(IB, Arg) &&
138 SPSArgList<SPSTagTs...>::deserialize(IB, Args...);
139 }
140};
141
142/// SPS serialization for integral types, bool, and char.
143template <typename SPSTagT>
144class SPSSerializationTraits<
145 SPSTagT, SPSTagT,
146 std::enable_if_t<std::is_same<SPSTagT, bool>::value ||
147 std::is_same<SPSTagT, char>::value ||
148 std::is_same<SPSTagT, int8_t>::value ||
149 std::is_same<SPSTagT, int16_t>::value ||
150 std::is_same<SPSTagT, int32_t>::value ||
151 std::is_same<SPSTagT, int64_t>::value ||
152 std::is_same<SPSTagT, uint8_t>::value ||
153 std::is_same<SPSTagT, uint16_t>::value ||
154 std::is_same<SPSTagT, uint32_t>::value ||
155 std::is_same<SPSTagT, uint64_t>::value>> {
156public:
157 static size_t size(const SPSTagT &Value) { return sizeof(SPSTagT); }
158
159 static bool serialize(SPSOutputBuffer &OB, const SPSTagT &Value) {
160 SPSTagT Tmp = Value;
161 if (IsBigEndianHost)
162 swapByteOrder(Tmp);
163 return OB.write(Data: reinterpret_cast<const char *>(&Tmp), Size: sizeof(Tmp));
164 }
165
166 static bool deserialize(SPSInputBuffer &IB, SPSTagT &Value) {
167 SPSTagT Tmp;
168 if (!IB.read(Data: reinterpret_cast<char *>(&Tmp), Size: sizeof(Tmp)))
169 return false;
170 if (IsBigEndianHost)
171 swapByteOrder(Tmp);
172 Value = Tmp;
173 return true;
174 }
175};
176
177/// Any empty placeholder suitable as a substitute for void when deserializing
178class SPSEmpty {};
179
180/// Represents an address in the executor.
181class SPSExecutorAddr {};
182
183/// SPS tag type for tuples.
184///
185/// A blob tuple should be serialized by serializing each of the elements in
186/// sequence.
187template <typename... SPSTagTs> class SPSTuple {
188public:
189 /// Convenience typedef of the corresponding arg list.
190 typedef SPSArgList<SPSTagTs...> AsArgList;
191};
192
193/// SPS tag type for optionals.
194///
195/// SPSOptionals should be serialized as a bool with true indicating that an
196/// SPSTagT value is present, and false indicating that there is no value.
197/// If the boolean is true then the serialized SPSTagT will follow immediately
198/// after it.
199template <typename SPSTagT> class SPSOptional {};
200
201/// SPS tag type for sequences.
202///
203/// SPSSequences should be serialized as a uint64_t sequence length,
204/// followed by the serialization of each of the elements.
205template <typename SPSElementTagT> class SPSSequence;
206
207/// SPS tag type for strings, which are equivalent to sequences of chars.
208using SPSString = SPSSequence<char>;
209
210/// SPS tag type for maps.
211///
212/// SPS maps are just sequences of (Key, Value) tuples.
213template <typename SPSTagT1, typename SPSTagT2>
214using SPSMap = SPSSequence<SPSTuple<SPSTagT1, SPSTagT2>>;
215
216/// Serialization for SPSEmpty type.
217template <> class SPSSerializationTraits<SPSEmpty, SPSEmpty> {
218public:
219 static size_t size(const SPSEmpty &EP) { return 0; }
220 static bool serialize(SPSOutputBuffer &OB, const SPSEmpty &BE) {
221 return true;
222 }
223 static bool deserialize(SPSInputBuffer &IB, SPSEmpty &BE) { return true; }
224};
225
226/// Specialize this to implement 'trivial' sequence serialization for
227/// a concrete sequence type.
228///
229/// Trivial sequence serialization uses the sequence's 'size' member to get the
230/// length of the sequence, and uses a range-based for loop to iterate over the
231/// elements.
232///
233/// Specializing this template class means that you do not need to provide a
234/// specialization of SPSSerializationTraits for your type.
235template <typename SPSElementTagT, typename ConcreteSequenceT>
236class TrivialSPSSequenceSerialization {
237public:
238 static constexpr bool available = false;
239};
240
241/// Specialize this to implement 'trivial' sequence deserialization for
242/// a concrete sequence type.
243///
244/// Trivial deserialization calls a static 'reserve(SequenceT&)' method on your
245/// specialization (you must implement this) to reserve space, and then calls
246/// a static 'append(SequenceT&, ElementT&) method to append each of the
247/// deserialized elements.
248///
249/// Specializing this template class means that you do not need to provide a
250/// specialization of SPSSerializationTraits for your type.
251template <typename SPSElementTagT, typename ConcreteSequenceT>
252class TrivialSPSSequenceDeserialization {
253public:
254 static constexpr bool available = false;
255};
256
257/// Trivial std::string -> SPSSequence<char> serialization.
258template <> class TrivialSPSSequenceSerialization<char, std::string> {
259public:
260 static constexpr bool available = true;
261};
262
263/// Trivial SPSSequence<char> -> std::string deserialization.
264template <> class TrivialSPSSequenceDeserialization<char, std::string> {
265public:
266 static constexpr bool available = true;
267
268 using element_type = char;
269
270 static void reserve(std::string &S, uint64_t Size) { S.reserve(res_arg: Size); }
271 static bool append(std::string &S, char C) {
272 S.push_back(c: C);
273 return true;
274 }
275};
276
277/// Trivial std::vector<T> -> SPSSequence<SPSElementTagT> serialization.
278template <typename SPSElementTagT, typename T>
279class TrivialSPSSequenceSerialization<SPSElementTagT, std::vector<T>> {
280public:
281 static constexpr bool available = true;
282};
283
284/// Trivial span<T> -> SPSSequence<SPSElementTagT> serialization.
285template <typename SPSElementTagT, typename T>
286class TrivialSPSSequenceSerialization<SPSElementTagT, span<T>> {
287public:
288 static constexpr bool available = true;
289};
290
291/// Trivial SPSSequence<SPSElementTagT> -> std::vector<T> deserialization.
292template <typename SPSElementTagT, typename T>
293class TrivialSPSSequenceDeserialization<SPSElementTagT, std::vector<T>> {
294public:
295 static constexpr bool available = true;
296
297 using element_type = typename std::vector<T>::value_type;
298
299 static void reserve(std::vector<T> &V, uint64_t Size) { V.reserve(Size); }
300 static bool append(std::vector<T> &V, T E) {
301 V.push_back(std::move(E));
302 return true;
303 }
304};
305
306/// Trivial std::unordered_map<K, V> -> SPSSequence<SPSTuple<SPSKey, SPSValue>>
307/// serialization.
308template <typename SPSKeyTagT, typename SPSValueTagT, typename K, typename V>
309class TrivialSPSSequenceSerialization<SPSTuple<SPSKeyTagT, SPSValueTagT>,
310 std::unordered_map<K, V>> {
311public:
312 static constexpr bool available = true;
313};
314
315/// Trivial SPSSequence<SPSTuple<SPSKey, SPSValue>> -> std::unordered_map<K, V>
316/// deserialization.
317template <typename SPSKeyTagT, typename SPSValueTagT, typename K, typename V>
318class TrivialSPSSequenceDeserialization<SPSTuple<SPSKeyTagT, SPSValueTagT>,
319 std::unordered_map<K, V>> {
320public:
321 static constexpr bool available = true;
322
323 using element_type = std::pair<K, V>;
324
325 static void reserve(std::unordered_map<K, V> &M, uint64_t Size) {
326 M.reserve(Size);
327 }
328 static bool append(std::unordered_map<K, V> &M, element_type E) {
329 return M.insert(std::move(E)).second;
330 }
331};
332
333/// 'Trivial' sequence serialization: Sequence is serialized as a uint64_t size
334/// followed by a for-earch loop over the elements of the sequence to serialize
335/// each of them.
336template <typename SPSElementTagT, typename SequenceT>
337class SPSSerializationTraits<SPSSequence<SPSElementTagT>, SequenceT,
338 std::enable_if_t<TrivialSPSSequenceSerialization<
339 SPSElementTagT, SequenceT>::available>> {
340public:
341 static size_t size(const SequenceT &S) {
342 size_t Size = SPSArgList<uint64_t>::size(Arg: static_cast<uint64_t>(S.size()));
343 for (const auto &E : S)
344 Size += SPSArgList<SPSElementTagT>::size(E);
345 return Size;
346 }
347
348 static bool serialize(SPSOutputBuffer &OB, const SequenceT &S) {
349 if (!SPSArgList<uint64_t>::serialize(OB, Arg: static_cast<uint64_t>(S.size())))
350 return false;
351 for (const auto &E : S)
352 if (!SPSArgList<SPSElementTagT>::serialize(OB, E))
353 return false;
354 return true;
355 }
356
357 static bool deserialize(SPSInputBuffer &IB, SequenceT &S) {
358 using TBSD = TrivialSPSSequenceDeserialization<SPSElementTagT, SequenceT>;
359 uint64_t Size;
360 if (!SPSArgList<uint64_t>::deserialize(IB, Arg&: Size))
361 return false;
362 TBSD::reserve(S, Size);
363 for (size_t I = 0; I != Size; ++I) {
364 typename TBSD::element_type E;
365 if (!SPSArgList<SPSElementTagT>::deserialize(IB, E))
366 return false;
367 if (!TBSD::append(S, std::move(E)))
368 return false;
369 }
370 return true;
371 }
372};
373
374/// Trivial serialization / deserialization for span<char>
375template <> class SPSSerializationTraits<SPSSequence<char>, span<const char>> {
376public:
377 static size_t size(const span<const char> &S) {
378 return SPSArgList<uint64_t>::size(Arg: static_cast<uint64_t>(S.size())) +
379 S.size();
380 }
381 static bool serialize(SPSOutputBuffer &OB, const span<const char> &S) {
382 if (!SPSArgList<uint64_t>::serialize(OB, Arg: static_cast<uint64_t>(S.size())))
383 return false;
384 return OB.write(Data: S.data(), Size: S.size());
385 }
386 static bool deserialize(SPSInputBuffer &IB, span<const char> &S) {
387 uint64_t Size;
388 if (!SPSArgList<uint64_t>::deserialize(IB, Arg&: Size))
389 return false;
390 S = span<const char>(IB.data(), Size);
391 return IB.skip(Size);
392 }
393};
394
395/// SPSTuple serialization for std::tuple.
396template <typename... SPSTagTs, typename... Ts>
397class SPSSerializationTraits<SPSTuple<SPSTagTs...>, std::tuple<Ts...>> {
398private:
399 using TupleArgList = typename SPSTuple<SPSTagTs...>::AsArgList;
400 using ArgIndices = std::make_index_sequence<sizeof...(Ts)>;
401
402 template <std::size_t... I>
403 static size_t size(const std::tuple<Ts...> &T, std::index_sequence<I...>) {
404 return TupleArgList::size(std::get<I>(T)...);
405 }
406
407 template <std::size_t... I>
408 static bool serialize(SPSOutputBuffer &OB, const std::tuple<Ts...> &T,
409 std::index_sequence<I...>) {
410 return TupleArgList::serialize(OB, std::get<I>(T)...);
411 }
412
413 template <std::size_t... I>
414 static bool deserialize(SPSInputBuffer &IB, std::tuple<Ts...> &T,
415 std::index_sequence<I...>) {
416 return TupleArgList::deserialize(IB, std::get<I>(T)...);
417 }
418
419public:
420 static size_t size(const std::tuple<Ts...> &T) {
421 return size(T, ArgIndices{});
422 }
423
424 static bool serialize(SPSOutputBuffer &OB, const std::tuple<Ts...> &T) {
425 return serialize(OB, T, ArgIndices{});
426 }
427
428 static bool deserialize(SPSInputBuffer &IB, std::tuple<Ts...> &T) {
429 return deserialize(IB, T, ArgIndices{});
430 }
431};
432
433/// SPSTuple serialization for std::pair.
434template <typename SPSTagT1, typename SPSTagT2, typename T1, typename T2>
435class SPSSerializationTraits<SPSTuple<SPSTagT1, SPSTagT2>, std::pair<T1, T2>> {
436public:
437 static size_t size(const std::pair<T1, T2> &P) {
438 return SPSArgList<SPSTagT1>::size(P.first) +
439 SPSArgList<SPSTagT2>::size(P.second);
440 }
441
442 static bool serialize(SPSOutputBuffer &OB, const std::pair<T1, T2> &P) {
443 return SPSArgList<SPSTagT1>::serialize(OB, P.first) &&
444 SPSArgList<SPSTagT2>::serialize(OB, P.second);
445 }
446
447 static bool deserialize(SPSInputBuffer &IB, std::pair<T1, T2> &P) {
448 return SPSArgList<SPSTagT1>::deserialize(IB, P.first) &&
449 SPSArgList<SPSTagT2>::deserialize(IB, P.second);
450 }
451};
452
453/// SPSOptional serialization for std::optional.
454template <typename SPSTagT, typename T>
455class SPSSerializationTraits<SPSOptional<SPSTagT>, std::optional<T>> {
456public:
457 static size_t size(const std::optional<T> &Value) {
458 size_t Size = SPSArgList<bool>::size(!!Value);
459 if (Value)
460 Size += SPSArgList<SPSTagT>::size(*Value);
461 return Size;
462 }
463
464 static bool serialize(SPSOutputBuffer &OB, const std::optional<T> &Value) {
465 if (!SPSArgList<bool>::serialize(OB, !!Value))
466 return false;
467 if (Value)
468 return SPSArgList<SPSTagT>::serialize(OB, *Value);
469 return true;
470 }
471
472 static bool deserialize(SPSInputBuffer &IB, std::optional<T> &Value) {
473 bool HasValue;
474 if (!SPSArgList<bool>::deserialize(IB, Arg&: HasValue))
475 return false;
476 if (HasValue) {
477 Value = T();
478 return SPSArgList<SPSTagT>::deserialize(IB, *Value);
479 } else
480 Value = std::optional<T>();
481 return true;
482 }
483};
484
485/// Serialization for string_views.
486///
487/// Serialization is as for regular strings. Deserialization points directly
488/// into the blob.
489template <> class SPSSerializationTraits<SPSString, std::string_view> {
490public:
491 static size_t size(const std::string_view &S) {
492 return SPSArgList<uint64_t>::size(Arg: static_cast<uint64_t>(S.size())) +
493 S.size();
494 }
495
496 static bool serialize(SPSOutputBuffer &OB, const std::string_view &S) {
497 if (!SPSArgList<uint64_t>::serialize(OB, Arg: static_cast<uint64_t>(S.size())))
498 return false;
499 return OB.write(Data: S.data(), Size: S.size());
500 }
501
502 static bool deserialize(SPSInputBuffer &IB, std::string_view &S) {
503 const char *Data = nullptr;
504 uint64_t Size;
505 if (!SPSArgList<uint64_t>::deserialize(IB, Arg&: Size))
506 return false;
507 if (Size > std::numeric_limits<size_t>::max())
508 return false;
509 Data = IB.data();
510 if (!IB.skip(Size))
511 return false;
512 S = {Data, static_cast<size_t>(Size)};
513 return true;
514 }
515};
516
517/// SPS tag type for errors.
518class SPSError;
519
520/// SPS tag type for expecteds, which are either a T or a string representing
521/// an error.
522template <typename SPSTagT> class SPSExpected;
523
524namespace detail {
525
526/// Helper type for serializing Errors.
527///
528/// llvm::Errors are move-only, and not inspectable except by consuming them.
529/// This makes them unsuitable for direct serialization via
530/// SPSSerializationTraits, which needs to inspect values twice (once to
531/// determine the amount of space to reserve, and then again to serialize).
532///
533/// The SPSSerializableError type is a helper that can be
534/// constructed from an llvm::Error, but inspected more than once.
535struct SPSSerializableError {
536 bool HasError = false;
537 std::string ErrMsg;
538};
539
540/// Helper type for serializing Expected<T>s.
541///
542/// See SPSSerializableError for more details.
543///
544// FIXME: Use std::variant for storage once we have c++17.
545template <typename T> struct SPSSerializableExpected {
546 bool HasValue = false;
547 T Value{};
548 std::string ErrMsg;
549};
550
551inline SPSSerializableError toSPSSerializable(Error Err) {
552 if (Err)
553 return {.HasError: true, .ErrMsg: toString(Err: std::move(Err))};
554 return {.HasError: false, .ErrMsg: {}};
555}
556
557inline Error fromSPSSerializable(SPSSerializableError BSE) {
558 if (BSE.HasError)
559 return make_error<StringError>(Args&: BSE.ErrMsg);
560 return Error::success();
561}
562
563template <typename T>
564SPSSerializableExpected<T> toSPSSerializable(Expected<T> E) {
565 if (E)
566 return {true, std::move(*E), {}};
567 else
568 return {false, {}, toString(E.takeError())};
569}
570
571template <typename T>
572Expected<T> fromSPSSerializable(SPSSerializableExpected<T> BSE) {
573 if (BSE.HasValue)
574 return std::move(BSE.Value);
575 else
576 return make_error<StringError>(BSE.ErrMsg);
577}
578
579} // end namespace detail
580
581/// Serialize to a SPSError from a detail::SPSSerializableError.
582template <>
583class SPSSerializationTraits<SPSError, detail::SPSSerializableError> {
584public:
585 static size_t size(const detail::SPSSerializableError &BSE) {
586 size_t Size = SPSArgList<bool>::size(Arg: BSE.HasError);
587 if (BSE.HasError)
588 Size += SPSArgList<SPSString>::size(Arg: BSE.ErrMsg);
589 return Size;
590 }
591
592 static bool serialize(SPSOutputBuffer &OB,
593 const detail::SPSSerializableError &BSE) {
594 if (!SPSArgList<bool>::serialize(OB, Arg: BSE.HasError))
595 return false;
596 if (BSE.HasError)
597 if (!SPSArgList<SPSString>::serialize(OB, Arg: BSE.ErrMsg))
598 return false;
599 return true;
600 }
601
602 static bool deserialize(SPSInputBuffer &IB,
603 detail::SPSSerializableError &BSE) {
604 if (!SPSArgList<bool>::deserialize(IB, Arg&: BSE.HasError))
605 return false;
606
607 if (!BSE.HasError)
608 return true;
609
610 return SPSArgList<SPSString>::deserialize(IB, Arg&: BSE.ErrMsg);
611 }
612};
613
614/// Serialize to a SPSExpected<SPSTagT> from a
615/// detail::SPSSerializableExpected<T>.
616template <typename SPSTagT, typename T>
617class SPSSerializationTraits<SPSExpected<SPSTagT>,
618 detail::SPSSerializableExpected<T>> {
619public:
620 static size_t size(const detail::SPSSerializableExpected<T> &BSE) {
621 size_t Size = SPSArgList<bool>::size(BSE.HasValue);
622 if (BSE.HasValue)
623 Size += SPSArgList<SPSTagT>::size(BSE.Value);
624 else
625 Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
626 return Size;
627 }
628
629 static bool serialize(SPSOutputBuffer &OB,
630 const detail::SPSSerializableExpected<T> &BSE) {
631 if (!SPSArgList<bool>::serialize(OB, BSE.HasValue))
632 return false;
633
634 if (BSE.HasValue)
635 return SPSArgList<SPSTagT>::serialize(OB, BSE.Value);
636
637 return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
638 }
639
640 static bool deserialize(SPSInputBuffer &IB,
641 detail::SPSSerializableExpected<T> &BSE) {
642 if (!SPSArgList<bool>::deserialize(IB, BSE.HasValue))
643 return false;
644
645 if (BSE.HasValue)
646 return SPSArgList<SPSTagT>::deserialize(IB, BSE.Value);
647
648 return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
649 }
650};
651
652/// Serialize to a SPSExpected<SPSTagT> from a detail::SPSSerializableError.
653template <typename SPSTagT>
654class SPSSerializationTraits<SPSExpected<SPSTagT>,
655 detail::SPSSerializableError> {
656public:
657 static size_t size(const detail::SPSSerializableError &BSE) {
658 assert(BSE.HasError && "Cannot serialize expected from a success value");
659 return SPSArgList<bool>::size(Arg: false) +
660 SPSArgList<SPSString>::size(Arg: BSE.ErrMsg);
661 }
662
663 static bool serialize(SPSOutputBuffer &OB,
664 const detail::SPSSerializableError &BSE) {
665 assert(BSE.HasError && "Cannot serialize expected from a success value");
666 if (!SPSArgList<bool>::serialize(OB, Arg: false))
667 return false;
668 return SPSArgList<SPSString>::serialize(OB, Arg: BSE.ErrMsg);
669 }
670};
671
672/// Serialize to a SPSExpected<SPSTagT> from a T.
673template <typename SPSTagT, typename T>
674class SPSSerializationTraits<SPSExpected<SPSTagT>, T> {
675public:
676 static size_t size(const T &Value) {
677 return SPSArgList<bool>::size(Arg: true) + SPSArgList<SPSTagT>::size(Value);
678 }
679
680 static bool serialize(SPSOutputBuffer &OB, const T &Value) {
681 if (!SPSArgList<bool>::serialize(OB, Arg: true))
682 return false;
683 return SPSArgList<SPSTagT>::serialize(Value);
684 }
685};
686
687} // end namespace __orc_rt
688
689#endif // ORC_RT_SIMPLE_PACKED_SERIALIZATION_H
690