//===- llvm/ExecutionEngine/Orc/RPCSerialization.h --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_EXECUTIONENGINE_ORC_RPCSERIALIZATION_H #define LLVM_EXECUTIONENGINE_ORC_RPCSERIALIZATION_H #include "OrcError.h" #include "llvm/Support/thread.h" #include #include namespace llvm { namespace orc { namespace rpc { template class RPCTypeName; /// TypeNameSequence is a utility for rendering sequences of types to a string /// by rendering each type, separated by ", ". template class RPCTypeNameSequence {}; /// Render an empty TypeNameSequence to an ostream. template OStream &operator<<(OStream &OS, const RPCTypeNameSequence<> &V) { return OS; } /// Render a TypeNameSequence of a single type to an ostream. template OStream &operator<<(OStream &OS, const RPCTypeNameSequence &V) { OS << RPCTypeName::getName(); return OS; } /// Render a TypeNameSequence of more than one type to an ostream. template OStream& operator<<(OStream &OS, const RPCTypeNameSequence &V) { OS << RPCTypeName::getName() << ", " << RPCTypeNameSequence(); return OS; } template <> class RPCTypeName { public: static const char* getName() { return "void"; } }; template <> class RPCTypeName { public: static const char* getName() { return "int8_t"; } }; template <> class RPCTypeName { public: static const char* getName() { return "uint8_t"; } }; template <> class RPCTypeName { public: static const char* getName() { return "int16_t"; } }; template <> class RPCTypeName { public: static const char* getName() { return "uint16_t"; } }; template <> class RPCTypeName { public: static const char* getName() { return "int32_t"; } }; template <> class RPCTypeName { public: static const char* getName() { return "uint32_t"; } }; template <> class RPCTypeName { public: static const char* getName() { return "int64_t"; } }; template <> class RPCTypeName { public: static const char* getName() { return "uint64_t"; } }; template <> class RPCTypeName { public: static const char* getName() { return "bool"; } }; template <> class RPCTypeName { public: static const char* getName() { return "std::string"; } }; template class RPCTypeName> { public: static const char* getName() { std::lock_guard Lock(NameMutex); if (Name.empty()) raw_string_ostream(Name) << "std::pair<" << RPCTypeNameSequence() << ">"; return Name.data(); } private: static std::mutex NameMutex; static std::string Name; }; template std::mutex RPCTypeName>::NameMutex; template std::string RPCTypeName>::Name; template class RPCTypeName> { public: static const char* getName() { std::lock_guard Lock(NameMutex); if (Name.empty()) raw_string_ostream(Name) << "std::tuple<" << RPCTypeNameSequence() << ">"; return Name.data(); } private: static std::mutex NameMutex; static std::string Name; }; template std::mutex RPCTypeName>::NameMutex; template std::string RPCTypeName>::Name; template class RPCTypeName> { public: static const char*getName() { std::lock_guard Lock(NameMutex); if (Name.empty()) raw_string_ostream(Name) << "std::vector<" << RPCTypeName::getName() << ">"; return Name.data(); } private: static std::mutex NameMutex; static std::string Name; }; template std::mutex RPCTypeName>::NameMutex; template std::string RPCTypeName>::Name; /// The SerializationTraits class describes how to serialize and /// deserialize an instance of type T to/from an abstract channel of type /// ChannelT. It also provides a representation of the type's name via the /// getName method. /// /// Specializations of this class should provide the following functions: /// /// @code{.cpp} /// /// static const char* getName(); /// static Error serialize(ChannelT&, const T&); /// static Error deserialize(ChannelT&, T&); /// /// @endcode /// /// The third argument of SerializationTraits is intended to support SFINAE. /// E.g.: /// /// @code{.cpp} /// /// class MyVirtualChannel { ... }; /// /// template /// class SerializationTraits::value /// >::type> { /// public: /// static const char* getName() { ... }; /// } /// /// @endcode template class SerializationTraits; template class SequenceTraits { public: static Error emitSeparator(ChannelT &C) { return Error::success(); } static Error consumeSeparator(ChannelT &C) { return Error::success(); } }; /// Utility class for serializing sequences of values of varying types. /// Specializations of this class contain 'serialize' and 'deserialize' methods /// for the given channel. The ArgTs... list will determine the "over-the-wire" /// types to be serialized. The serialize and deserialize methods take a list /// CArgTs... ("caller arg types") which must be the same length as ArgTs..., /// but may be different types from ArgTs, provided that for each CArgT there /// is a SerializationTraits specialization /// SerializeTraits with methods that can serialize the /// caller argument to over-the-wire value. template class SequenceSerialization; template class SequenceSerialization { public: static Error serialize(ChannelT &C) { return Error::success(); } static Error deserialize(ChannelT &C) { return Error::success(); } }; template class SequenceSerialization { public: template static Error serialize(ChannelT &C, const CArgT &CArg) { return SerializationTraits::serialize(C, CArg); } template static Error deserialize(ChannelT &C, CArgT &CArg) { return SerializationTraits::deserialize(C, CArg); } }; template class SequenceSerialization { public: template static Error serialize(ChannelT &C, const CArgT &CArg, const CArgTs&... CArgs) { if (auto Err = SerializationTraits::serialize(C, CArg)) return Err; if (auto Err = SequenceTraits::emitSeparator(C)) return Err; return SequenceSerialization::serialize(C, CArgs...); } template static Error deserialize(ChannelT &C, CArgT &CArg, CArgTs&... CArgs) { if (auto Err = SerializationTraits::deserialize(C, CArg)) return Err; if (auto Err = SequenceTraits::consumeSeparator(C)) return Err; return SequenceSerialization::deserialize(C, CArgs...); } }; template Error serializeSeq(ChannelT &C, const ArgTs &... Args) { return SequenceSerialization::serialize(C, Args...); } template Error deserializeSeq(ChannelT &C, ArgTs &... Args) { return SequenceSerialization::deserialize(C, Args...); } /// SerializationTraits default specialization for std::pair. template class SerializationTraits> { public: static Error serialize(ChannelT &C, const std::pair &V) { return serializeSeq(C, V.first, V.second); } static Error deserialize(ChannelT &C, std::pair &V) { return deserializeSeq(C, V.first, V.second); } }; /// SerializationTraits default specialization for std::tuple. template class SerializationTraits> { public: /// RPC channel serialization for std::tuple. static Error serialize(ChannelT &C, const std::tuple &V) { return serializeTupleHelper(C, V, llvm::index_sequence_for()); } /// RPC channel deserialization for std::tuple. static Error deserialize(ChannelT &C, std::tuple &V) { return deserializeTupleHelper(C, V, llvm::index_sequence_for()); } private: // Serialization helper for std::tuple. template static Error serializeTupleHelper(ChannelT &C, const std::tuple &V, llvm::index_sequence _) { return serializeSeq(C, std::get(V)...); } // Serialization helper for std::tuple. template static Error deserializeTupleHelper(ChannelT &C, std::tuple &V, llvm::index_sequence _) { return deserializeSeq(C, std::get(V)...); } }; /// SerializationTraits default specialization for std::vector. template class SerializationTraits> { public: /// Serialize a std::vector from std::vector. static Error serialize(ChannelT &C, const std::vector &V) { if (auto Err = serializeSeq(C, static_cast(V.size()))) return Err; for (const auto &E : V) if (auto Err = serializeSeq(C, E)) return Err; return Error::success(); } /// Deserialize a std::vector to a std::vector. static Error deserialize(ChannelT &C, std::vector &V) { uint64_t Count = 0; if (auto Err = deserializeSeq(C, Count)) return Err; V.resize(Count); for (auto &E : V) if (auto Err = deserializeSeq(C, E)) return Err; return Error::success(); } }; } // end namespace rpc } // end namespace orc } // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_RPCSERIALIZATION_H