Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 104 additions & 110 deletions orc-rt/include/orc-rt/SimplePackedSerialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -513,12 +513,6 @@ template <> class SPSSerializationTraits<SPSString, std::string_view> {
/// SPS tag type for errors.
class SPSError;

/// SPS tag type for expecteds, which are either a T or a string representing
/// an error.
template <typename SPSTagT> class SPSExpected;

namespace detail {

/// Helper type for serializing Errors.
///
/// llvm::Errors are move-only, and not inspectable except by consuming them.
Expand All @@ -529,139 +523,141 @@ namespace detail {
/// The SPSSerializableError type is a helper that can be
/// constructed from an llvm::Error, but inspected more than once.
struct SPSSerializableError {
bool HasError = false;
std::string ErrMsg;
};

/// Helper type for serializing Expected<T>s.
///
/// See SPSSerializableError for more details.
///
// FIXME: Use std::variant for storage once we have c++17.
template <typename T> struct SPSSerializableExpected {
bool HasValue = false;
T Value{};
std::string ErrMsg;
};

inline SPSSerializableError toSPSSerializable(Error Err) {
if (Err)
return {true, toString(std::move(Err))};
return {false, {}};
}

inline Error fromSPSSerializable(SPSSerializableError BSE) {
if (BSE.HasError)
return make_error<StringError>(BSE.ErrMsg);
return Error::success();
}

template <typename T>
SPSSerializableExpected<T> toSPSSerializable(Expected<T> E) {
if (E)
return {true, std::move(*E), {}};
else
return {false, {}, toString(E.takeError())};
}
SPSSerializableError() = default;
SPSSerializableError(Error Err) {
if (Err)
Msg = toString(std::move(Err));
}

template <typename T>
Expected<T> fromSPSSerializable(SPSSerializableExpected<T> BSE) {
if (BSE.HasValue)
return std::move(BSE.Value);
else
return make_error<StringError>(BSE.ErrMsg);
}
Error toError() {
if (Msg)
return make_error<StringError>(std::move(*Msg));
return Error::success();
}

} // namespace detail
std::optional<std::string> Msg;
};

/// Serialize to a SPSError from a detail::SPSSerializableError.
template <>
class SPSSerializationTraits<SPSError, detail::SPSSerializableError> {
template <> class SPSSerializationTraits<SPSError, SPSSerializableError> {
public:
static size_t size(const detail::SPSSerializableError &BSE) {
size_t Size = SPSArgList<bool>::size(BSE.HasError);
if (BSE.HasError)
Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
return Size;
static size_t size(const SPSSerializableError &E) {
if (E.Msg)
return SPSArgList<bool, SPSString>::size(true, *E.Msg);
else
return SPSArgList<bool>::size(false);
}

static bool serialize(SPSOutputBuffer &OB,
const detail::SPSSerializableError &BSE) {
if (!SPSArgList<bool>::serialize(OB, BSE.HasError))
static bool serialize(SPSOutputBuffer &OB, const SPSSerializableError &E) {
if (E.Msg)
return SPSArgList<bool, SPSString>::serialize(OB, true, *E.Msg);
else
return SPSArgList<bool>::serialize(OB, false);
}

static bool deserialize(SPSInputBuffer &IB, SPSSerializableError &E) {
bool HasError = false;
if (!SPSArgList<bool>::deserialize(IB, HasError))
return false;
if (BSE.HasError)
if (!SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg))
if (HasError) {
std::string Msg;
if (!SPSArgList<SPSString>::deserialize(IB, Msg))
return false;
E.Msg = std::move(Msg);
} else
E.Msg = std::nullopt;
return true;
}
};

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

if (!BSE.HasError)
return true;
/// Helper type for serializing Expected<T>s.
///
/// See SPSSerializableError for more details.
template <typename T> struct SPSSerializableExpected {
SPSSerializableExpected() = default;
SPSSerializableExpected(Expected<T> E) {
if (E)
Val = decltype(Val)(std::in_place_index<0>, std::move(*E));
else
Val = decltype(Val)(std::in_place_index<1>, toString(E.takeError()));
}
SPSSerializableExpected(Error E) {
assert(E && "Cannot create Expected from Error::success()");
Val = decltype(Val)(std::in_place_index<1>, toString(std::move(E)));
}

return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
Expected<T> toExpected() {
if (Val.index() == 0)
return Expected<T>(std::move(std::get<0>(Val)));
return Expected<T>(make_error<StringError>(std::move(std::get<1>(Val))));
}

std::variant<T, std::string> Val{std::in_place_index<0>, T()};
};

/// Serialize to a SPSExpected<SPSTagT> from a
/// detail::SPSSerializableExpected<T>.
template <typename T>
SPSSerializableExpected<T> toSPSSerializableExpected(Expected<T> E) {
return std::move(E);
}

template <typename T>
SPSSerializableExpected<T> toSPSSerializableExpected(Error E) {
return std::move(E);
}

template <typename SPSTagT, typename T>
class SPSSerializationTraits<SPSExpected<SPSTagT>,
detail::SPSSerializableExpected<T>> {
class SPSSerializationTraits<SPSExpected<SPSTagT>, SPSSerializableExpected<T>> {
public:
static size_t size(const detail::SPSSerializableExpected<T> &BSE) {
size_t Size = SPSArgList<bool>::size(BSE.HasValue);
if (BSE.HasValue)
Size += SPSArgList<SPSTagT>::size(BSE.Value);
static size_t size(const SPSSerializableExpected<T> &E) {
if (E.Val.index() == 0)
return SPSArgList<bool, SPSTagT>::size(true, std::get<0>(E.Val));
else
Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
return Size;
return SPSArgList<bool, SPSString>::size(false, std::get<1>(E.Val));
}

static bool serialize(SPSOutputBuffer &OB,
const detail::SPSSerializableExpected<T> &BSE) {
if (!SPSArgList<bool>::serialize(OB, BSE.HasValue))
return false;

if (BSE.HasValue)
return SPSArgList<SPSTagT>::serialize(OB, BSE.Value);

return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
const SPSSerializableExpected<T> &E) {
if (E.Val.index() == 0)
return SPSArgList<bool, SPSTagT>::serialize(OB, true, std::get<0>(E.Val));
else
return SPSArgList<bool, SPSString>::serialize(OB, false,
std::get<1>(E.Val));
}

static bool deserialize(SPSInputBuffer &IB,
detail::SPSSerializableExpected<T> &BSE) {
if (!SPSArgList<bool>::deserialize(IB, BSE.HasValue))
static bool deserialize(SPSInputBuffer &IB, SPSSerializableExpected<T> &E) {
bool HasValue = false;
if (!SPSArgList<bool>::deserialize(IB, HasValue))
return false;

if (BSE.HasValue)
return SPSArgList<SPSTagT>::deserialize(IB, BSE.Value);

return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
if (HasValue) {
T Val;
if (!SPSArgList<SPSTagT>::deserialize(IB, Val))
return false;
E.Val = decltype(E.Val){std::in_place_index<0>, std::move(Val)};
} else {
std::string Msg;
if (!SPSArgList<SPSString>::deserialize(IB, Msg))
return false;
E.Val = decltype(E.Val){std::in_place_index<1>, std::move(Msg)};
}
return true;
}
};

/// Serialize to a SPSExpected<SPSTagT> from a detail::SPSSerializableError.
/// Serialize to a SPSExpected<SPSTagT> from a SPSSerializableError.
template <typename SPSTagT>
class SPSSerializationTraits<SPSExpected<SPSTagT>,
detail::SPSSerializableError> {
class SPSSerializationTraits<SPSExpected<SPSTagT>, SPSSerializableError> {
public:
static size_t size(const detail::SPSSerializableError &BSE) {
assert(BSE.HasError && "Cannot serialize expected from a success value");
return SPSArgList<bool>::size(false) +
SPSArgList<SPSString>::size(BSE.ErrMsg);
static size_t size(const SPSSerializableError &SE) {
assert(SE.Msg && "Cannot serialize expected from a success value");
return SPSArgList<bool, SPSString>::size(false, *SE.Msg);
}

static bool serialize(SPSOutputBuffer &OB,
const detail::SPSSerializableError &BSE) {
assert(BSE.HasError && "Cannot serialize expected from a success value");
if (!SPSArgList<bool>::serialize(OB, false))
return false;
return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
static bool serialize(SPSOutputBuffer &OB, const SPSSerializableError &SE) {
assert(SE.Msg && "Cannot serialize expected from a success value");
return SPSArgList<bool, SPSString>::serialize(OB, false, *SE.Msg);
}
};

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

static bool serialize(SPSOutputBuffer &OB, const T &Value) {
if (!SPSArgList<bool>::serialize(OB, true))
return false;
return SPSArgList<SPSTagT>::serialize(Value);
return SPSArgList<bool, SPSTagT>::serialize(OB, true, Value);
}
};

Expand Down
75 changes: 75 additions & 0 deletions orc-rt/unittests/SimplePackedSerializationTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#include "orc-rt/SimplePackedSerialization.h"

#include "SimplePackedSerializationTestUtils.h"
#include "gtest/gtest.h"

Expand Down Expand Up @@ -182,3 +183,77 @@ TEST(SimplePackedSerializationTest, ArgListSerialization) {
EXPECT_EQ(Arg2, ArgOut2);
EXPECT_EQ(Arg3, ArgOut3);
}

TEST(SimplePackedSerializationTest, SerializeErrorSuccess) {
auto B = spsSerialize<SPSArgList<SPSError>>(
SPSSerializableError(Error::success()));
if (!B) {
ADD_FAILURE() << "Unexpected failure to serialize error-success value";
return;
}
SPSSerializableError SE;
if (!spsDeserialize<SPSArgList<SPSError>>(*B, SE)) {
ADD_FAILURE() << "Unexpected failure to deserialize error-success value";
return;
}

auto E = SE.toError();
EXPECT_FALSE(!!E); // Expect non-error, i.e. Error::success().
}

TEST(SimplePackedSerializationTest, SerializeErrorFailure) {
auto B = spsSerialize<SPSArgList<SPSError>>(
SPSSerializableError(make_error<StringError>("test error message")));
if (!B) {
ADD_FAILURE() << "Unexpected failure to serialize error-failure value";
return;
}
SPSSerializableError SE;
if (!spsDeserialize<SPSArgList<SPSError>>(*B, SE)) {
ADD_FAILURE() << "Unexpected failure to deserialize error-failure value";
return;
}

EXPECT_EQ(toString(SE.toError()), std::string("test error message"));
}

TEST(SimplePackedSerializationTest, SerializeExpectedSuccess) {
auto B = spsSerialize<SPSArgList<SPSExpected<uint32_t>>>(
toSPSSerializableExpected(Expected<uint32_t>(42U)));
if (!B) {
ADD_FAILURE() << "Unexpected failure to serialize expected-success value";
return;
}
SPSSerializableExpected<uint32_t> SE;
if (!spsDeserialize<SPSArgList<SPSExpected<uint32_t>>>(*B, SE)) {
ADD_FAILURE() << "Unexpected failure to deserialize expected-success value";
return;
}

auto E = SE.toExpected();
if (E)
EXPECT_EQ(*E, 42U);
else
ADD_FAILURE() << "Unexpected failure value";
}

TEST(SimplePackedSerializationTest, SerializeExpectedFailure) {
auto B = spsSerialize<SPSArgList<SPSExpected<uint32_t>>>(
toSPSSerializableExpected<uint32_t>(
make_error<StringError>("test error message")));
if (!B) {
ADD_FAILURE() << "Unexpected failure to serialize expected-failure value";
return;
}
SPSSerializableExpected<uint32_t> SE;
if (!spsDeserialize<SPSArgList<SPSExpected<uint32_t>>>(*B, SE)) {
ADD_FAILURE() << "Unexpected failure to deserialize expected-failure value";
return;
}

auto E = SE.toExpected();
if (E)
ADD_FAILURE() << "Unexpected failure value";
else
EXPECT_EQ(toString(E.takeError()), std::string("test error message"));
}
21 changes: 20 additions & 1 deletion orc-rt/unittests/SimplePackedSerializationTestUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,29 @@
#define ORC_RT_UNITTEST_SIMPLEPACKEDSERIALIZATIONTESTUTILS_H

#include "orc-rt/SimplePackedSerialization.h"
#include "orc-rt/WrapperFunction.h"
#include "gtest/gtest.h"

#include <optional>

template <typename SPSTraitsT, typename... ArgTs>
static inline std::optional<orc_rt::WrapperFunctionBuffer>
spsSerialize(const ArgTs &...Args) {
auto B = orc_rt::WrapperFunctionBuffer::allocate(SPSTraitsT::size(Args...));
orc_rt::SPSOutputBuffer OB(B.data(), B.size());
if (!SPSTraitsT::serialize(OB, Args...))
return std::nullopt;
return B;
}

template <typename SPSTraitsT, typename... ArgTs>
static bool spsDeserialize(orc_rt::WrapperFunctionBuffer &B, ArgTs &...Args) {
orc_rt::SPSInputBuffer IB(B.data(), B.size());
return SPSTraitsT::deserialize(IB, Args...);
}

template <typename SPSTagT, typename T>
static void blobSerializationRoundTrip(const T &Value) {
static inline void blobSerializationRoundTrip(const T &Value) {
using BST = orc_rt::SPSSerializationTraits<SPSTagT, T>;

size_t Size = BST::size(Value);
Expand Down
Loading