| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,207 @@ | ||
| // -*- c++ -*- | ||
|
|
||
| #ifndef LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H | ||
| #define LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H | ||
|
|
||
| #include "OrcError.h" | ||
| #include "llvm/ADT/ArrayRef.h" | ||
| #include "llvm/Support/Endian.h" | ||
|
|
||
| #include <system_error> | ||
| #include <unistd.h> | ||
|
|
||
| namespace llvm { | ||
| namespace orc { | ||
| namespace remote { | ||
|
|
||
| /// Interface for byte-streams to be used with RPC. | ||
| class RPCChannel { | ||
| public: | ||
| virtual ~RPCChannel() {} | ||
|
|
||
| /// Read Size bytes from the stream into *Dst. | ||
| virtual std::error_code readBytes(char *Dst, unsigned Size) = 0; | ||
|
|
||
| /// Read size bytes from *Src and append them to the stream. | ||
| virtual std::error_code appendBytes(const char *Src, unsigned Size) = 0; | ||
|
|
||
| /// Flush the stream if possible. | ||
| virtual std::error_code send() = 0; | ||
| }; | ||
|
|
||
| /// RPC channel that reads from and writes from file descriptors. | ||
| class FDRPCChannel : public RPCChannel { | ||
| public: | ||
| FDRPCChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {} | ||
|
|
||
| std::error_code readBytes(char *Dst, unsigned Size) override { | ||
| assert(Dst && "Attempt to read into null."); | ||
| ssize_t ReadResult = ::read(InFD, Dst, Size); | ||
| if (ReadResult != Size) | ||
| return std::error_code(errno, std::generic_category()); | ||
| return std::error_code(); | ||
| } | ||
|
|
||
| std::error_code appendBytes(const char *Src, unsigned Size) override { | ||
| assert(Src && "Attempt to append from null."); | ||
| ssize_t WriteResult = ::write(OutFD, Src, Size); | ||
| if (WriteResult != Size) | ||
| std::error_code(errno, std::generic_category()); | ||
| return std::error_code(); | ||
| } | ||
|
|
||
| std::error_code send() override { return std::error_code(); } | ||
|
|
||
| private: | ||
| int InFD, OutFD; | ||
| }; | ||
|
|
||
| /// RPC channel serialization for a variadic list of arguments. | ||
| template <typename T, typename... Ts> | ||
| std::error_code serialize_seq(RPCChannel &C, const T &Arg, const Ts &... Args) { | ||
| if (auto EC = serialize(C, Arg)) | ||
| return EC; | ||
| return serialize_seq(C, Args...); | ||
| } | ||
|
|
||
| /// RPC channel serialization for an (empty) variadic list of arguments. | ||
| inline std::error_code serialize_seq(RPCChannel &C) { | ||
| return std::error_code(); | ||
| } | ||
|
|
||
| /// RPC channel deserialization for a variadic list of arguments. | ||
| template <typename T, typename... Ts> | ||
| std::error_code deserialize_seq(RPCChannel &C, T &Arg, Ts &... Args) { | ||
| if (auto EC = deserialize(C, Arg)) | ||
| return EC; | ||
| return deserialize_seq(C, Args...); | ||
| } | ||
|
|
||
| /// RPC channel serialization for an (empty) variadic list of arguments. | ||
| inline std::error_code deserialize_seq(RPCChannel &C) { | ||
| return std::error_code(); | ||
| } | ||
|
|
||
| /// RPC channel serialization for integer primitives. | ||
| template <typename T> | ||
| typename std::enable_if< | ||
| std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value || | ||
| std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value || | ||
| std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value || | ||
| std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value, | ||
| std::error_code>::type | ||
| serialize(RPCChannel &C, T V) { | ||
| support::endian::byte_swap<T, support::big>(V); | ||
| return C.appendBytes(reinterpret_cast<const char *>(&V), sizeof(T)); | ||
| } | ||
|
|
||
| /// RPC channel deserialization for integer primitives. | ||
| template <typename T> | ||
| typename std::enable_if< | ||
| std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value || | ||
| std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value || | ||
| std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value || | ||
| std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value, | ||
| std::error_code>::type | ||
| deserialize(RPCChannel &C, T &V) { | ||
| if (auto EC = C.readBytes(reinterpret_cast<char *>(&V), sizeof(T))) | ||
| return EC; | ||
| support::endian::byte_swap<T, support::big>(V); | ||
| return std::error_code(); | ||
| } | ||
|
|
||
| /// RPC channel serialization for enums. | ||
| template <typename T> | ||
| typename std::enable_if<std::is_enum<T>::value, std::error_code>::type | ||
| serialize(RPCChannel &C, T V) { | ||
| return serialize(C, static_cast<typename std::underlying_type<T>::type>(V)); | ||
| } | ||
|
|
||
| /// RPC channel deserialization for enums. | ||
| template <typename T> | ||
| typename std::enable_if<std::is_enum<T>::value, std::error_code>::type | ||
| deserialize(RPCChannel &C, T &V) { | ||
| typename std::underlying_type<T>::type Tmp; | ||
| std::error_code EC = deserialize(C, Tmp); | ||
| V = static_cast<T>(Tmp); | ||
| return EC; | ||
| } | ||
|
|
||
| /// RPC channel serialization for bools. | ||
| inline std::error_code serialize(RPCChannel &C, bool V) { | ||
| uint8_t VN = V ? 1 : 0; | ||
| return C.appendBytes(reinterpret_cast<const char *>(&VN), 1); | ||
| } | ||
|
|
||
| /// RPC channel deserialization for bools. | ||
| inline std::error_code deserialize(RPCChannel &C, bool &V) { | ||
| uint8_t VN = 0; | ||
| if (auto EC = C.readBytes(reinterpret_cast<char *>(&VN), 1)) | ||
| return EC; | ||
|
|
||
| V = (VN != 0) ? true : false; | ||
| return std::error_code(); | ||
| } | ||
|
|
||
| /// RPC channel serialization for StringRefs. | ||
| /// Note: There is no corresponding deseralization for this, as StringRef | ||
| /// doesn't own its memory and so can't hold the deserialized data. | ||
| inline std::error_code serialize(RPCChannel &C, StringRef S) { | ||
| if (auto EC = serialize(C, static_cast<uint64_t>(S.size()))) | ||
| return EC; | ||
| return C.appendBytes((const char *)S.bytes_begin(), S.size()); | ||
| } | ||
|
|
||
| /// RPC channel serialization for std::strings. | ||
| inline std::error_code serialize(RPCChannel &C, const std::string &S) { | ||
| return serialize(C, StringRef(S)); | ||
| } | ||
|
|
||
| /// RPC channel deserialization for std::strings. | ||
| inline std::error_code deserialize(RPCChannel &C, std::string &S) { | ||
| uint64_t Count; | ||
| if (auto EC = deserialize(C, Count)) | ||
| return EC; | ||
| S.resize(Count); | ||
| return C.readBytes(&S[0], Count); | ||
| } | ||
|
|
||
| /// RPC channel serialization for ArrayRef<T>. | ||
| template <typename T> | ||
| std::error_code serialize(RPCChannel &C, const ArrayRef<T> &A) { | ||
| if (auto EC = serialize(C, static_cast<uint64_t>(A.size()))) | ||
| return EC; | ||
|
|
||
| for (const auto &E : A) | ||
| if (auto EC = serialize(C, E)) | ||
| return EC; | ||
|
|
||
| return std::error_code(); | ||
| } | ||
|
|
||
| /// RPC channel serialization for std::array<T>. | ||
| template <typename T> | ||
| std::error_code serialize(RPCChannel &C, const std::vector<T> &V) { | ||
| return serialize(C, ArrayRef<T>(V)); | ||
| } | ||
|
|
||
| /// RPC channel deserialization for std::array<T>. | ||
| template <typename T> | ||
| std::error_code deserialize(RPCChannel &C, std::vector<T> &V) { | ||
| uint64_t Count = 0; | ||
| if (auto EC = deserialize(C, Count)) | ||
| return EC; | ||
|
|
||
| V.resize(Count); | ||
| for (auto &E : V) | ||
| if (auto EC = deserialize(C, E)) | ||
| return EC; | ||
|
|
||
| return std::error_code(); | ||
| } | ||
|
|
||
| } // end namespace remote | ||
| } // end namespace orc | ||
| } // end namespace llvm | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,222 @@ | ||
| //===----- RPCUTils.h - Basic tilities for building RPC APIs ----*- C++ -*-===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Basic utilities for building RPC APIs. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H | ||
| #define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H | ||
|
|
||
| #include "llvm/ADT/STLExtras.h" | ||
|
|
||
| namespace llvm { | ||
| namespace orc { | ||
| namespace remote { | ||
|
|
||
| /// Contains primitive utilities for defining, calling and handling calls to | ||
| /// remote procedures. ChannelT is a bidirectional stream conforming to the | ||
| /// RPCChannel interface (see RPCChannel.h), and ProcedureIdT is a procedure | ||
| /// identifier type that must be serializable on ChannelT. | ||
| /// | ||
| /// These utilities support the construction of very primitive RPC utilities. | ||
| /// Their intent is to ensure correct serialization and deserialization of | ||
| /// procedure arguments, and to keep the client and server's view of the API in | ||
| /// sync. | ||
| /// | ||
| /// These utilities do not support return values. These can be handled by | ||
| /// declaring a corresponding '.*Response' procedure and expecting it after a | ||
| /// call). They also do not support versioning: the client and server *must* be | ||
| /// compiled with the same procedure definitions. | ||
| /// | ||
| /// | ||
| /// | ||
| /// Overview (see comments individual types/methods for details): | ||
| /// | ||
| /// Procedure<Id, Args...> : | ||
| /// | ||
| /// associates a unique serializable id with an argument list. | ||
| /// | ||
| /// | ||
| /// call<Proc>(Channel, Args...) : | ||
| /// | ||
| /// Calls the remote procedure 'Proc' by serializing Proc's id followed by its | ||
| /// arguments and sending the resulting bytes to 'Channel'. | ||
| /// | ||
| /// | ||
| /// handle<Proc>(Channel, <functor matching std::error_code(Args...)> : | ||
| /// | ||
| /// Handles a call to 'Proc' by deserializing its arguments and calling the | ||
| /// given functor. This assumes that the id for 'Proc' has already been | ||
| /// deserialized. | ||
| /// | ||
| /// expect<Proc>(Channel, <functor matching std::error_code(Args...)> : | ||
| /// | ||
| /// The same as 'handle', except that the procedure id should not have been | ||
| /// read yet. Expect will deserialize the id and assert that it matches Proc's | ||
| /// id. If it does not, and unexpected RPC call error is returned. | ||
|
|
||
| template <typename ChannelT, typename ProcedureIdT = uint32_t> class RPC { | ||
| public: | ||
| /// Utility class for defining/referring to RPC procedures. | ||
| /// | ||
| /// Typedefs of this utility are used when calling/handling remote procedures. | ||
| /// | ||
| /// ProcId should be a unique value of ProcedureIdT (i.e. not used with any | ||
| /// other Procedure typedef in the RPC API being defined. | ||
| /// | ||
| /// the template argument Ts... gives the argument list for the remote | ||
| /// procedure. | ||
| /// | ||
| /// E.g. | ||
| /// | ||
| /// typedef Procedure<0, bool> Proc1; | ||
| /// typedef Procedure<1, std::string, std::vector<int>> Proc2; | ||
| /// | ||
| /// if (auto EC = call<Proc1>(Channel, true)) | ||
| /// /* handle EC */; | ||
| /// | ||
| /// if (auto EC = expect<Proc2>(Channel, | ||
| /// [](std::string &S, std::vector<int> &V) { | ||
| /// // Stuff. | ||
| /// return std::error_code(); | ||
| /// }) | ||
| /// /* handle EC */; | ||
| /// | ||
| template <ProcedureIdT ProcId, typename... Ts> class Procedure { | ||
| public: | ||
| static const ProcedureIdT Id = ProcId; | ||
| }; | ||
|
|
||
| private: | ||
| template <typename Proc> class CallHelper {}; | ||
|
|
||
| template <ProcedureIdT ProcId, typename... ArgTs> | ||
| class CallHelper<Procedure<ProcId, ArgTs...>> { | ||
| public: | ||
| static std::error_code call(ChannelT &C, const ArgTs &... Args) { | ||
| if (auto EC = serialize(C, ProcId)) | ||
| return EC; | ||
| // If you see a compile-error on this line you're probably calling a | ||
| // function with the wrong signature. | ||
| return serialize_seq(C, Args...); | ||
| } | ||
| }; | ||
|
|
||
| template <typename Proc> class HandlerHelper {}; | ||
|
|
||
| template <ProcedureIdT ProcId, typename... ArgTs> | ||
| class HandlerHelper<Procedure<ProcId, ArgTs...>> { | ||
| public: | ||
| template <typename HandlerT> | ||
| static std::error_code handle(ChannelT &C, HandlerT Handler) { | ||
| return readAndHandle(C, Handler, llvm::index_sequence_for<ArgTs...>()); | ||
| } | ||
|
|
||
| private: | ||
| template <typename HandlerT, size_t... Is> | ||
| static std::error_code readAndHandle(ChannelT &C, HandlerT Handler, | ||
| llvm::index_sequence<Is...> _) { | ||
| std::tuple<ArgTs...> RPCArgs; | ||
| if (auto EC = deserialize_seq(C, std::get<Is>(RPCArgs)...)) | ||
| return EC; | ||
| return Handler(std::get<Is>(RPCArgs)...); | ||
| } | ||
| }; | ||
|
|
||
| template <typename... ArgTs> class ReadArgs { | ||
| public: | ||
| std::error_code operator()() { return std::error_code(); } | ||
| }; | ||
|
|
||
| template <typename ArgT, typename... ArgTs> | ||
| class ReadArgs<ArgT, ArgTs...> : public ReadArgs<ArgTs...> { | ||
| public: | ||
| ReadArgs(ArgT &Arg, ArgTs &... Args) | ||
| : ReadArgs<ArgTs...>(Args...), Arg(Arg) {} | ||
|
|
||
| std::error_code operator()(ArgT &ArgVal, ArgTs &... ArgVals) { | ||
| this->Arg = std::move(ArgVal); | ||
| return ReadArgs<ArgTs...>::operator()(ArgVals...); | ||
| } | ||
|
|
||
| private: | ||
| ArgT &Arg; | ||
| }; | ||
|
|
||
| public: | ||
| /// Serialize Args... to channel C, but do not call C.send(). | ||
| /// | ||
| /// For buffered channels, this can be used to queue up several calls before | ||
| /// flushing the channel. | ||
| template <typename Proc, typename... ArgTs> | ||
| static std::error_code appendCall(ChannelT &C, const ArgTs &... Args) { | ||
| return CallHelper<Proc>::call(C, Args...); | ||
| } | ||
|
|
||
| /// Serialize Args... to channel C and call C.send(). | ||
| template <typename Proc, typename... ArgTs> | ||
| static std::error_code call(ChannelT &C, const ArgTs &... Args) { | ||
| if (auto EC = appendCall<Proc>(C, Args...)) | ||
| return EC; | ||
| return C.send(); | ||
| } | ||
|
|
||
| /// Deserialize and return an enum whose underlying type is ProcedureIdT. | ||
| static std::error_code getNextProcId(ChannelT &C, ProcedureIdT &Id) { | ||
| return deserialize(C, Id); | ||
| } | ||
|
|
||
| /// Deserialize args for Proc from C and call Handler. The signature of | ||
| /// handler must conform to 'std::error_code(Args...)' where Args... matches | ||
| /// the arguments used in the Proc typedef. | ||
| template <typename Proc, typename HandlerT> | ||
| static std::error_code handle(ChannelT &C, HandlerT Handler) { | ||
| return HandlerHelper<Proc>::handle(C, Handler); | ||
| } | ||
|
|
||
| /// Deserialize a ProcedureIdT from C and verify it matches the id for Proc. | ||
| /// If the id does match, deserialize the arguments and call the handler | ||
| /// (similarly to handle). | ||
| /// If the id does not match, return an unexpect RPC call error and do not | ||
| /// deserialize any further bytes. | ||
| template <typename Proc, typename HandlerT> | ||
| static std::error_code expect(ChannelT &C, HandlerT Handler) { | ||
| ProcedureIdT ProcId; | ||
| if (auto EC = getNextProcId(C, ProcId)) | ||
| return EC; | ||
| if (ProcId != Proc::Id) | ||
| return orcError(OrcErrorCode::UnexpectedRPCCall); | ||
| return handle<Proc>(C, Handler); | ||
| } | ||
|
|
||
| /// Helper for handling setter procedures - this method returns a functor that | ||
| /// sets the variables referred to by Args... to values deserialized from the | ||
| /// channel. | ||
| /// E.g. | ||
| /// | ||
| /// typedef Procedure<0, bool, int> Proc1; | ||
| /// | ||
| /// ... | ||
| /// bool B; | ||
| /// int I; | ||
| /// if (auto EC = expect<Proc1>(Channel, readArgs(B, I))) | ||
| /// /* Handle Args */ ; | ||
| /// | ||
| template <typename... ArgTs> | ||
| static ReadArgs<ArgTs...> readArgs(ArgTs &... Args) { | ||
| return ReadArgs<ArgTs...>(Args...); | ||
| } | ||
| }; | ||
|
|
||
| } // end namespace remote | ||
| } // end namespace orc | ||
| } // end namespace llvm | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| //===------- OrcRemoteTargetRPCAPI.cpp - ORC Remote API utilities ---------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h" | ||
|
|
||
| namespace llvm { | ||
| namespace orc { | ||
| namespace remote { | ||
|
|
||
| const char *OrcRemoteTargetRPCAPI::getJITProcIdName(JITProcId Id) { | ||
| switch (Id) { | ||
| case InvalidId: | ||
| return "*** Invalid JITProcId ***"; | ||
| case CallIntVoidId: | ||
| return "CallIntVoid"; | ||
| case CallIntVoidResponseId: | ||
| return "CallIntVoidResponse"; | ||
| case CallMainId: | ||
| return "CallMain"; | ||
| case CallMainResponseId: | ||
| return "CallMainResponse"; | ||
| case CallVoidVoidId: | ||
| return "CallVoidVoid"; | ||
| case CallVoidVoidResponseId: | ||
| return "CallVoidVoidResponse"; | ||
| case CreateRemoteAllocatorId: | ||
| return "CreateRemoteAllocator"; | ||
| case CreateIndirectStubsOwnerId: | ||
| return "CreateIndirectStubsOwner"; | ||
| case DestroyRemoteAllocatorId: | ||
| return "DestroyRemoteAllocator"; | ||
| case DestroyIndirectStubsOwnerId: | ||
| return "DestroyIndirectStubsOwner"; | ||
| case EmitIndirectStubsId: | ||
| return "EmitIndirectStubs"; | ||
| case EmitIndirectStubsResponseId: | ||
| return "EmitIndirectStubsResponse"; | ||
| case EmitResolverBlockId: | ||
| return "EmitResolverBlock"; | ||
| case EmitTrampolineBlockId: | ||
| return "EmitTrampolineBlock"; | ||
| case EmitTrampolineBlockResponseId: | ||
| return "EmitTrampolineBlockResponse"; | ||
| case GetSymbolAddressId: | ||
| return "GetSymbolAddress"; | ||
| case GetSymbolAddressResponseId: | ||
| return "GetSymbolAddressResponse"; | ||
| case GetRemoteInfoId: | ||
| return "GetRemoteInfo"; | ||
| case GetRemoteInfoResponseId: | ||
| return "GetRemoteInfoResponse"; | ||
| case ReadMemId: | ||
| return "ReadMem"; | ||
| case ReadMemResponseId: | ||
| return "ReadMemResponse"; | ||
| case ReserveMemId: | ||
| return "ReserveMem"; | ||
| case ReserveMemResponseId: | ||
| return "ReserveMemResponse"; | ||
| case RequestCompileId: | ||
| return "RequestCompile"; | ||
| case RequestCompileResponseId: | ||
| return "RequestCompileResponse"; | ||
| case SetProtectionsId: | ||
| return "SetProtections"; | ||
| case TerminateSessionId: | ||
| return "TerminateSession"; | ||
| case WriteMemId: | ||
| return "WriteMem"; | ||
| case WritePtrId: | ||
| return "WritePtr"; | ||
| }; | ||
| return nullptr; | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,4 +18,5 @@ add_llvm_unittest(OrcJITTests | |
| ObjectTransformLayerTest.cpp | ||
| OrcCAPITest.cpp | ||
| OrcTestCommon.cpp | ||
| RPCUtilsTest.cpp | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| //===----------- RPCUtilsTest.cpp - Unit tests the Orc RPC utils ----------===// | ||
| // | ||
| // The LLVM Compiler Infrastructure | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "llvm/ExecutionEngine/Orc/RPCChannel.h" | ||
| #include "llvm/ExecutionEngine/Orc/RPCUtils.h" | ||
| #include "gtest/gtest.h" | ||
|
|
||
| #include <queue> | ||
|
|
||
| using namespace llvm; | ||
| using namespace llvm::orc; | ||
| using namespace llvm::orc::remote; | ||
|
|
||
| class QueueChannel : public RPCChannel { | ||
| public: | ||
| QueueChannel(std::queue<char> &Queue) : Queue(Queue) {} | ||
|
|
||
| std::error_code readBytes(char *Dst, unsigned Size) override { | ||
| while (Size--) { | ||
| *Dst++ = Queue.front(); | ||
| Queue.pop(); | ||
| } | ||
| return std::error_code(); | ||
| } | ||
|
|
||
| std::error_code appendBytes(const char *Src, unsigned Size) override { | ||
| while (Size--) | ||
| Queue.push(*Src++); | ||
| return std::error_code(); | ||
| } | ||
|
|
||
| std::error_code send() override { return std::error_code(); } | ||
|
|
||
| private: | ||
| std::queue<char> &Queue; | ||
| }; | ||
|
|
||
| class DummyRPC : public testing::Test, | ||
| public RPC<QueueChannel> { | ||
| public: | ||
| typedef Procedure<1, bool> Proc1; | ||
| typedef Procedure<2, int8_t, | ||
| uint8_t, | ||
| int16_t, | ||
| uint16_t, | ||
| int32_t, | ||
| uint32_t, | ||
| int64_t, | ||
| uint64_t, | ||
| bool, | ||
| std::string, | ||
| std::vector<int>> AllTheTypes; | ||
| }; | ||
|
|
||
|
|
||
| TEST_F(DummyRPC, TestBasic) { | ||
| std::queue<char> Queue; | ||
| QueueChannel C(Queue); | ||
|
|
||
| { | ||
| // Make a call to Proc1. | ||
| auto EC = call<Proc1>(C, true); | ||
| EXPECT_FALSE(EC) << "Simple call over queue failed"; | ||
| } | ||
|
|
||
| { | ||
| // Expect a call to Proc1. | ||
| auto EC = expect<Proc1>(C, | ||
| [&](bool &B) { | ||
| EXPECT_EQ(B, true) | ||
| << "Bool serialization broken"; | ||
| return std::error_code(); | ||
| }); | ||
| EXPECT_FALSE(EC) << "Simple expect over queue failed"; | ||
| } | ||
| } | ||
|
|
||
| TEST_F(DummyRPC, TestSerialization) { | ||
| std::queue<char> Queue; | ||
| QueueChannel C(Queue); | ||
|
|
||
| { | ||
| // Make a call to Proc1. | ||
| std::vector<int> v({42, 7}); | ||
| auto EC = call<AllTheTypes>(C, | ||
| -101, | ||
| 250, | ||
| -10000, | ||
| 10000, | ||
| -1000000000, | ||
| 1000000000, | ||
| -10000000000, | ||
| 10000000000, | ||
| true, | ||
| "foo", | ||
| v); | ||
| EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed"; | ||
| } | ||
|
|
||
| { | ||
| // Expect a call to Proc1. | ||
| auto EC = expect<AllTheTypes>(C, | ||
| [&](int8_t &s8, | ||
| uint8_t &u8, | ||
| int16_t &s16, | ||
| uint16_t &u16, | ||
| int32_t &s32, | ||
| uint32_t &u32, | ||
| int64_t &s64, | ||
| uint64_t &u64, | ||
| bool &b, | ||
| std::string &s, | ||
| std::vector<int> &v) { | ||
|
|
||
| EXPECT_EQ(s8, -101) | ||
| << "int8_t serialization broken"; | ||
| EXPECT_EQ(u8, 250) | ||
| << "uint8_t serialization broken"; | ||
| EXPECT_EQ(s16, -10000) | ||
| << "int16_t serialization broken"; | ||
| EXPECT_EQ(u16, 10000) | ||
| << "uint16_t serialization broken"; | ||
| EXPECT_EQ(s32, -1000000000) | ||
| << "int32_t serialization broken"; | ||
| EXPECT_EQ(u32, 1000000000ULL) | ||
| << "uint32_t serialization broken"; | ||
| EXPECT_EQ(s64, -10000000000) | ||
| << "int64_t serialization broken"; | ||
| EXPECT_EQ(u64, 10000000000ULL) | ||
| << "uint64_t serialization broken"; | ||
| EXPECT_EQ(b, true) | ||
| << "bool serialization broken"; | ||
| EXPECT_EQ(s, "foo") | ||
| << "std::string serialization broken"; | ||
| EXPECT_EQ(v, std::vector<int>({42, 7})) | ||
| << "std::vector serialization broken"; | ||
| return std::error_code(); | ||
| }); | ||
| EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed"; | ||
| } | ||
| } |