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 51 namespace __orc_rt { 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 118 // Non-empty list specialization for SPSArgList. 119 template <typename SPSTagT, typename... SPSTagTs> 120 class SPSArgList<SPSTagT, SPSTagTs...> { 121 public: 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. 143 template <typename SPSTagT> 144 class 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>> { 156 public: 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(reinterpret_cast<const char *>(&Tmp), sizeof(Tmp)); 164 } 165 166 static bool deserialize(SPSInputBuffer &IB, SPSTagT &Value) { 167 SPSTagT Tmp; 168 if (!IB.read(reinterpret_cast<char *>(&Tmp), 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 178 class SPSEmpty {}; 179 180 /// Represents an address in the executor. 181 class 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. 187 template <typename... SPSTagTs> class SPSTuple { 188 public: 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. 199 template <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. 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 span<T> -> SPSSequence<SPSElementTagT> serialization. 285 template <typename SPSElementTagT, typename T> 286 class TrivialSPSSequenceSerialization<SPSElementTagT, span<T>> { 287 public: 288 static constexpr bool available = true; 289 }; 290 291 /// Trivial SPSSequence<SPSElementTagT> -> std::vector<T> deserialization. 292 template <typename SPSElementTagT, typename T> 293 class TrivialSPSSequenceDeserialization<SPSElementTagT, std::vector<T>> { 294 public: 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. 308 template <typename SPSKeyTagT, typename SPSValueTagT, typename K, typename V> 309 class TrivialSPSSequenceSerialization<SPSTuple<SPSKeyTagT, SPSValueTagT>, 310 std::unordered_map<K, V>> { 311 public: 312 static constexpr bool available = true; 313 }; 314 315 /// Trivial SPSSequence<SPSTuple<SPSKey, SPSValue>> -> std::unordered_map<K, V> 316 /// deserialization. 317 template <typename SPSKeyTagT, typename SPSValueTagT, typename K, typename V> 318 class TrivialSPSSequenceDeserialization<SPSTuple<SPSKeyTagT, SPSValueTagT>, 319 std::unordered_map<K, V>> { 320 public: 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. 336 template <typename SPSElementTagT, typename SequenceT> 337 class SPSSerializationTraits<SPSSequence<SPSElementTagT>, SequenceT, 338 std::enable_if_t<TrivialSPSSequenceSerialization< 339 SPSElementTagT, SequenceT>::available>> { 340 public: 341 static size_t size(const SequenceT &S) { 342 size_t Size = SPSArgList<uint64_t>::size(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, 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, 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> 375 template <> class SPSSerializationTraits<SPSSequence<char>, span<const char>> { 376 public: 377 static size_t size(const span<const char> &S) { 378 return SPSArgList<uint64_t>::size(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, static_cast<uint64_t>(S.size()))) 383 return false; 384 return OB.write(S.data(), S.size()); 385 } 386 static bool deserialize(SPSInputBuffer &IB, span<const char> &S) { 387 uint64_t Size; 388 if (!SPSArgList<uint64_t>::deserialize(IB, 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. 396 template <typename... SPSTagTs, typename... Ts> 397 class SPSSerializationTraits<SPSTuple<SPSTagTs...>, std::tuple<Ts...>> { 398 private: 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 419 public: 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. 434 template <typename SPSTagT1, typename SPSTagT2, typename T1, typename T2> 435 class SPSSerializationTraits<SPSTuple<SPSTagT1, SPSTagT2>, std::pair<T1, T2>> { 436 public: 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. 454 template <typename SPSTagT, typename T> 455 class SPSSerializationTraits<SPSOptional<SPSTagT>, std::optional<T>> { 456 public: 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, 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. 489 template <> class SPSSerializationTraits<SPSString, std::string_view> { 490 public: 491 static size_t size(const std::string_view &S) { 492 return SPSArgList<uint64_t>::size(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, static_cast<uint64_t>(S.size()))) 498 return false; 499 return OB.write(S.data(), 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, 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. 518 class SPSError; 519 520 /// SPS tag type for expecteds, which are either a T or a string representing 521 /// an error. 522 template <typename SPSTagT> class SPSExpected; 523 524 namespace 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. 535 struct 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. 545 template <typename T> struct SPSSerializableExpected { 546 bool HasValue = false; 547 T Value{}; 548 std::string ErrMsg; 549 }; 550 551 inline SPSSerializableError toSPSSerializable(Error Err) { 552 if (Err) 553 return {true, toString(std::move(Err))}; 554 return {false, {}}; 555 } 556 557 inline Error fromSPSSerializable(SPSSerializableError BSE) { 558 if (BSE.HasError) 559 return make_error<StringError>(BSE.ErrMsg); 560 return Error::success(); 561 } 562 563 template <typename T> 564 SPSSerializableExpected<T> toSPSSerializable(Expected<T> E) { 565 if (E) 566 return {true, std::move(*E), {}}; 567 else 568 return {false, {}, toString(E.takeError())}; 569 } 570 571 template <typename T> 572 Expected<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. 582 template <> 583 class SPSSerializationTraits<SPSError, detail::SPSSerializableError> { 584 public: 585 static size_t size(const detail::SPSSerializableError &BSE) { 586 size_t Size = SPSArgList<bool>::size(BSE.HasError); 587 if (BSE.HasError) 588 Size += SPSArgList<SPSString>::size(BSE.ErrMsg); 589 return Size; 590 } 591 592 static bool serialize(SPSOutputBuffer &OB, 593 const detail::SPSSerializableError &BSE) { 594 if (!SPSArgList<bool>::serialize(OB, BSE.HasError)) 595 return false; 596 if (BSE.HasError) 597 if (!SPSArgList<SPSString>::serialize(OB, 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, BSE.HasError)) 605 return false; 606 607 if (!BSE.HasError) 608 return true; 609 610 return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg); 611 } 612 }; 613 614 /// Serialize to a SPSExpected<SPSTagT> from a 615 /// detail::SPSSerializableExpected<T>. 616 template <typename SPSTagT, typename T> 617 class SPSSerializationTraits<SPSExpected<SPSTagT>, 618 detail::SPSSerializableExpected<T>> { 619 public: 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. 653 template <typename SPSTagT> 654 class SPSSerializationTraits<SPSExpected<SPSTagT>, 655 detail::SPSSerializableError> { 656 public: 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(false) + 660 SPSArgList<SPSString>::size(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, false)) 667 return false; 668 return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg); 669 } 670 }; 671 672 /// Serialize to a SPSExpected<SPSTagT> from a T. 673 template <typename SPSTagT, typename T> 674 class SPSSerializationTraits<SPSExpected<SPSTagT>, T> { 675 public: 676 static size_t size(const T &Value) { 677 return SPSArgList<bool>::size(true) + SPSArgList<SPSTagT>::size(Value); 678 } 679 680 static bool serialize(SPSOutputBuffer &OB, const T &Value) { 681 if (!SPSArgList<bool>::serialize(OB, 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