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