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