Skip to content

Commit 2b73dad

Browse files
authored
[orc-rt] Clean up SPS serialization for Error, Expected; add testcase. (#157029)
This commit cleans up the SPS serialization code for Error and Expected, and adds test cases for success and failure values of each.
1 parent 5901d89 commit 2b73dad

File tree

3 files changed

+199
-111
lines changed

3 files changed

+199
-111
lines changed

orc-rt/include/orc-rt/SimplePackedSerialization.h

Lines changed: 104 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -513,12 +513,6 @@ template <> class SPSSerializationTraits<SPSString, std::string_view> {
513513
/// SPS tag type for errors.
514514
class SPSError;
515515

516-
/// SPS tag type for expecteds, which are either a T or a string representing
517-
/// an error.
518-
template <typename SPSTagT> class SPSExpected;
519-
520-
namespace detail {
521-
522516
/// Helper type for serializing Errors.
523517
///
524518
/// llvm::Errors are move-only, and not inspectable except by consuming them.
@@ -529,139 +523,141 @@ namespace detail {
529523
/// The SPSSerializableError type is a helper that can be
530524
/// constructed from an llvm::Error, but inspected more than once.
531525
struct SPSSerializableError {
532-
bool HasError = false;
533-
std::string ErrMsg;
534-
};
535-
536-
/// Helper type for serializing Expected<T>s.
537-
///
538-
/// See SPSSerializableError for more details.
539-
///
540-
// FIXME: Use std::variant for storage once we have c++17.
541-
template <typename T> struct SPSSerializableExpected {
542-
bool HasValue = false;
543-
T Value{};
544-
std::string ErrMsg;
545-
};
546-
547-
inline SPSSerializableError toSPSSerializable(Error Err) {
548-
if (Err)
549-
return {true, toString(std::move(Err))};
550-
return {false, {}};
551-
}
552-
553-
inline Error fromSPSSerializable(SPSSerializableError BSE) {
554-
if (BSE.HasError)
555-
return make_error<StringError>(BSE.ErrMsg);
556-
return Error::success();
557-
}
558-
559-
template <typename T>
560-
SPSSerializableExpected<T> toSPSSerializable(Expected<T> E) {
561-
if (E)
562-
return {true, std::move(*E), {}};
563-
else
564-
return {false, {}, toString(E.takeError())};
565-
}
526+
SPSSerializableError() = default;
527+
SPSSerializableError(Error Err) {
528+
if (Err)
529+
Msg = toString(std::move(Err));
530+
}
566531

567-
template <typename T>
568-
Expected<T> fromSPSSerializable(SPSSerializableExpected<T> BSE) {
569-
if (BSE.HasValue)
570-
return std::move(BSE.Value);
571-
else
572-
return make_error<StringError>(BSE.ErrMsg);
573-
}
532+
Error toError() {
533+
if (Msg)
534+
return make_error<StringError>(std::move(*Msg));
535+
return Error::success();
536+
}
574537

575-
} // namespace detail
538+
std::optional<std::string> Msg;
539+
};
576540

577-
/// Serialize to a SPSError from a detail::SPSSerializableError.
578-
template <>
579-
class SPSSerializationTraits<SPSError, detail::SPSSerializableError> {
541+
template <> class SPSSerializationTraits<SPSError, SPSSerializableError> {
580542
public:
581-
static size_t size(const detail::SPSSerializableError &BSE) {
582-
size_t Size = SPSArgList<bool>::size(BSE.HasError);
583-
if (BSE.HasError)
584-
Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
585-
return Size;
543+
static size_t size(const SPSSerializableError &E) {
544+
if (E.Msg)
545+
return SPSArgList<bool, SPSString>::size(true, *E.Msg);
546+
else
547+
return SPSArgList<bool>::size(false);
586548
}
587549

588-
static bool serialize(SPSOutputBuffer &OB,
589-
const detail::SPSSerializableError &BSE) {
590-
if (!SPSArgList<bool>::serialize(OB, BSE.HasError))
550+
static bool serialize(SPSOutputBuffer &OB, const SPSSerializableError &E) {
551+
if (E.Msg)
552+
return SPSArgList<bool, SPSString>::serialize(OB, true, *E.Msg);
553+
else
554+
return SPSArgList<bool>::serialize(OB, false);
555+
}
556+
557+
static bool deserialize(SPSInputBuffer &IB, SPSSerializableError &E) {
558+
bool HasError = false;
559+
if (!SPSArgList<bool>::deserialize(IB, HasError))
591560
return false;
592-
if (BSE.HasError)
593-
if (!SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg))
561+
if (HasError) {
562+
std::string Msg;
563+
if (!SPSArgList<SPSString>::deserialize(IB, Msg))
594564
return false;
565+
E.Msg = std::move(Msg);
566+
} else
567+
E.Msg = std::nullopt;
595568
return true;
596569
}
570+
};
597571

598-
static bool deserialize(SPSInputBuffer &IB,
599-
detail::SPSSerializableError &BSE) {
600-
if (!SPSArgList<bool>::deserialize(IB, BSE.HasError))
601-
return false;
572+
/// SPS tag type for expecteds, which are either a T or a string representing
573+
/// an error.
574+
template <typename SPSTagT> class SPSExpected;
602575

603-
if (!BSE.HasError)
604-
return true;
576+
/// Helper type for serializing Expected<T>s.
577+
///
578+
/// See SPSSerializableError for more details.
579+
template <typename T> struct SPSSerializableExpected {
580+
SPSSerializableExpected() = default;
581+
SPSSerializableExpected(Expected<T> E) {
582+
if (E)
583+
Val = decltype(Val)(std::in_place_index<0>, std::move(*E));
584+
else
585+
Val = decltype(Val)(std::in_place_index<1>, toString(E.takeError()));
586+
}
587+
SPSSerializableExpected(Error E) {
588+
assert(E && "Cannot create Expected from Error::success()");
589+
Val = decltype(Val)(std::in_place_index<1>, toString(std::move(E)));
590+
}
605591

606-
return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
592+
Expected<T> toExpected() {
593+
if (Val.index() == 0)
594+
return Expected<T>(std::move(std::get<0>(Val)));
595+
return Expected<T>(make_error<StringError>(std::move(std::get<1>(Val))));
607596
}
597+
598+
std::variant<T, std::string> Val{std::in_place_index<0>, T()};
608599
};
609600

610-
/// Serialize to a SPSExpected<SPSTagT> from a
611-
/// detail::SPSSerializableExpected<T>.
601+
template <typename T>
602+
SPSSerializableExpected<T> toSPSSerializableExpected(Expected<T> E) {
603+
return std::move(E);
604+
}
605+
606+
template <typename T>
607+
SPSSerializableExpected<T> toSPSSerializableExpected(Error E) {
608+
return std::move(E);
609+
}
610+
612611
template <typename SPSTagT, typename T>
613-
class SPSSerializationTraits<SPSExpected<SPSTagT>,
614-
detail::SPSSerializableExpected<T>> {
612+
class SPSSerializationTraits<SPSExpected<SPSTagT>, SPSSerializableExpected<T>> {
615613
public:
616-
static size_t size(const detail::SPSSerializableExpected<T> &BSE) {
617-
size_t Size = SPSArgList<bool>::size(BSE.HasValue);
618-
if (BSE.HasValue)
619-
Size += SPSArgList<SPSTagT>::size(BSE.Value);
614+
static size_t size(const SPSSerializableExpected<T> &E) {
615+
if (E.Val.index() == 0)
616+
return SPSArgList<bool, SPSTagT>::size(true, std::get<0>(E.Val));
620617
else
621-
Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
622-
return Size;
618+
return SPSArgList<bool, SPSString>::size(false, std::get<1>(E.Val));
623619
}
624620

625621
static bool serialize(SPSOutputBuffer &OB,
626-
const detail::SPSSerializableExpected<T> &BSE) {
627-
if (!SPSArgList<bool>::serialize(OB, BSE.HasValue))
628-
return false;
629-
630-
if (BSE.HasValue)
631-
return SPSArgList<SPSTagT>::serialize(OB, BSE.Value);
632-
633-
return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
622+
const SPSSerializableExpected<T> &E) {
623+
if (E.Val.index() == 0)
624+
return SPSArgList<bool, SPSTagT>::serialize(OB, true, std::get<0>(E.Val));
625+
else
626+
return SPSArgList<bool, SPSString>::serialize(OB, false,
627+
std::get<1>(E.Val));
634628
}
635629

636-
static bool deserialize(SPSInputBuffer &IB,
637-
detail::SPSSerializableExpected<T> &BSE) {
638-
if (!SPSArgList<bool>::deserialize(IB, BSE.HasValue))
630+
static bool deserialize(SPSInputBuffer &IB, SPSSerializableExpected<T> &E) {
631+
bool HasValue = false;
632+
if (!SPSArgList<bool>::deserialize(IB, HasValue))
639633
return false;
640-
641-
if (BSE.HasValue)
642-
return SPSArgList<SPSTagT>::deserialize(IB, BSE.Value);
643-
644-
return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
634+
if (HasValue) {
635+
T Val;
636+
if (!SPSArgList<SPSTagT>::deserialize(IB, Val))
637+
return false;
638+
E.Val = decltype(E.Val){std::in_place_index<0>, std::move(Val)};
639+
} else {
640+
std::string Msg;
641+
if (!SPSArgList<SPSString>::deserialize(IB, Msg))
642+
return false;
643+
E.Val = decltype(E.Val){std::in_place_index<1>, std::move(Msg)};
644+
}
645+
return true;
645646
}
646647
};
647648

648-
/// Serialize to a SPSExpected<SPSTagT> from a detail::SPSSerializableError.
649+
/// Serialize to a SPSExpected<SPSTagT> from a SPSSerializableError.
649650
template <typename SPSTagT>
650-
class SPSSerializationTraits<SPSExpected<SPSTagT>,
651-
detail::SPSSerializableError> {
651+
class SPSSerializationTraits<SPSExpected<SPSTagT>, SPSSerializableError> {
652652
public:
653-
static size_t size(const detail::SPSSerializableError &BSE) {
654-
assert(BSE.HasError && "Cannot serialize expected from a success value");
655-
return SPSArgList<bool>::size(false) +
656-
SPSArgList<SPSString>::size(BSE.ErrMsg);
653+
static size_t size(const SPSSerializableError &SE) {
654+
assert(SE.Msg && "Cannot serialize expected from a success value");
655+
return SPSArgList<bool, SPSString>::size(false, *SE.Msg);
657656
}
658657

659-
static bool serialize(SPSOutputBuffer &OB,
660-
const detail::SPSSerializableError &BSE) {
661-
assert(BSE.HasError && "Cannot serialize expected from a success value");
662-
if (!SPSArgList<bool>::serialize(OB, false))
663-
return false;
664-
return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
658+
static bool serialize(SPSOutputBuffer &OB, const SPSSerializableError &SE) {
659+
assert(SE.Msg && "Cannot serialize expected from a success value");
660+
return SPSArgList<bool, SPSString>::serialize(OB, false, *SE.Msg);
665661
}
666662
};
667663

@@ -674,9 +670,7 @@ class SPSSerializationTraits<SPSExpected<SPSTagT>, T> {
674670
}
675671

676672
static bool serialize(SPSOutputBuffer &OB, const T &Value) {
677-
if (!SPSArgList<bool>::serialize(OB, true))
678-
return false;
679-
return SPSArgList<SPSTagT>::serialize(Value);
673+
return SPSArgList<bool, SPSTagT>::serialize(OB, true, Value);
680674
}
681675
};
682676

orc-rt/unittests/SimplePackedSerializationTest.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "orc-rt/SimplePackedSerialization.h"
14+
1415
#include "SimplePackedSerializationTestUtils.h"
1516
#include "gtest/gtest.h"
1617

@@ -182,3 +183,77 @@ TEST(SimplePackedSerializationTest, ArgListSerialization) {
182183
EXPECT_EQ(Arg2, ArgOut2);
183184
EXPECT_EQ(Arg3, ArgOut3);
184185
}
186+
187+
TEST(SimplePackedSerializationTest, SerializeErrorSuccess) {
188+
auto B = spsSerialize<SPSArgList<SPSError>>(
189+
SPSSerializableError(Error::success()));
190+
if (!B) {
191+
ADD_FAILURE() << "Unexpected failure to serialize error-success value";
192+
return;
193+
}
194+
SPSSerializableError SE;
195+
if (!spsDeserialize<SPSArgList<SPSError>>(*B, SE)) {
196+
ADD_FAILURE() << "Unexpected failure to deserialize error-success value";
197+
return;
198+
}
199+
200+
auto E = SE.toError();
201+
EXPECT_FALSE(!!E); // Expect non-error, i.e. Error::success().
202+
}
203+
204+
TEST(SimplePackedSerializationTest, SerializeErrorFailure) {
205+
auto B = spsSerialize<SPSArgList<SPSError>>(
206+
SPSSerializableError(make_error<StringError>("test error message")));
207+
if (!B) {
208+
ADD_FAILURE() << "Unexpected failure to serialize error-failure value";
209+
return;
210+
}
211+
SPSSerializableError SE;
212+
if (!spsDeserialize<SPSArgList<SPSError>>(*B, SE)) {
213+
ADD_FAILURE() << "Unexpected failure to deserialize error-failure value";
214+
return;
215+
}
216+
217+
EXPECT_EQ(toString(SE.toError()), std::string("test error message"));
218+
}
219+
220+
TEST(SimplePackedSerializationTest, SerializeExpectedSuccess) {
221+
auto B = spsSerialize<SPSArgList<SPSExpected<uint32_t>>>(
222+
toSPSSerializableExpected(Expected<uint32_t>(42U)));
223+
if (!B) {
224+
ADD_FAILURE() << "Unexpected failure to serialize expected-success value";
225+
return;
226+
}
227+
SPSSerializableExpected<uint32_t> SE;
228+
if (!spsDeserialize<SPSArgList<SPSExpected<uint32_t>>>(*B, SE)) {
229+
ADD_FAILURE() << "Unexpected failure to deserialize expected-success value";
230+
return;
231+
}
232+
233+
auto E = SE.toExpected();
234+
if (E)
235+
EXPECT_EQ(*E, 42U);
236+
else
237+
ADD_FAILURE() << "Unexpected failure value";
238+
}
239+
240+
TEST(SimplePackedSerializationTest, SerializeExpectedFailure) {
241+
auto B = spsSerialize<SPSArgList<SPSExpected<uint32_t>>>(
242+
toSPSSerializableExpected<uint32_t>(
243+
make_error<StringError>("test error message")));
244+
if (!B) {
245+
ADD_FAILURE() << "Unexpected failure to serialize expected-failure value";
246+
return;
247+
}
248+
SPSSerializableExpected<uint32_t> SE;
249+
if (!spsDeserialize<SPSArgList<SPSExpected<uint32_t>>>(*B, SE)) {
250+
ADD_FAILURE() << "Unexpected failure to deserialize expected-failure value";
251+
return;
252+
}
253+
254+
auto E = SE.toExpected();
255+
if (E)
256+
ADD_FAILURE() << "Unexpected failure value";
257+
else
258+
EXPECT_EQ(toString(E.takeError()), std::string("test error message"));
259+
}

orc-rt/unittests/SimplePackedSerializationTestUtils.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,29 @@
1010
#define ORC_RT_UNITTEST_SIMPLEPACKEDSERIALIZATIONTESTUTILS_H
1111

1212
#include "orc-rt/SimplePackedSerialization.h"
13+
#include "orc-rt/WrapperFunction.h"
1314
#include "gtest/gtest.h"
1415

16+
#include <optional>
17+
18+
template <typename SPSTraitsT, typename... ArgTs>
19+
static inline std::optional<orc_rt::WrapperFunctionBuffer>
20+
spsSerialize(const ArgTs &...Args) {
21+
auto B = orc_rt::WrapperFunctionBuffer::allocate(SPSTraitsT::size(Args...));
22+
orc_rt::SPSOutputBuffer OB(B.data(), B.size());
23+
if (!SPSTraitsT::serialize(OB, Args...))
24+
return std::nullopt;
25+
return B;
26+
}
27+
28+
template <typename SPSTraitsT, typename... ArgTs>
29+
static bool spsDeserialize(orc_rt::WrapperFunctionBuffer &B, ArgTs &...Args) {
30+
orc_rt::SPSInputBuffer IB(B.data(), B.size());
31+
return SPSTraitsT::deserialize(IB, Args...);
32+
}
33+
1534
template <typename SPSTagT, typename T>
16-
static void blobSerializationRoundTrip(const T &Value) {
35+
static inline void blobSerializationRoundTrip(const T &Value) {
1736
using BST = orc_rt::SPSSerializationTraits<SPSTagT, T>;
1837

1938
size_t Size = BST::size(Value);

0 commit comments

Comments
 (0)