llvm/llvm/include/llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h

//===---- SimplePackedSerialization.h - simple serialization ----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// The behavior of the utilities in this header must be synchronized with the
// behavior of the utilities in
// compiler-rt/lib/orc/simple_packed_serialization.h.
//
// The Simple Packed Serialization (SPS) utilities are used to generate
// argument and return buffers for wrapper functions using the following
// serialization scheme:
//
// Primitives (signed types should be two's complement):
//   bool, char, int8_t, uint8_t -- 8-bit (0=false, 1=true)
//   int16_t, uint16_t           -- 16-bit little endian
//   int32_t, uint32_t           -- 32-bit little endian
//   int64_t, int64_t            -- 64-bit little endian
//
// Sequence<T>:
//   Serialized as the sequence length (as a uint64_t) followed by the
//   serialization of each of the elements without padding.
//
// Tuple<T1, ..., TN>:
//   Serialized as each of the element types from T1 to TN without padding.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEPACKEDSERIALIZATION_H
#define LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEPACKEDSERIALIZATION_H

#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/SwapByteOrder.h"

#include <limits>
#include <optional>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>

namespace llvm {
namespace orc {
namespace shared {

/// Output char buffer with overflow check.
class SPSOutputBuffer {};

/// Input char buffer with underflow check.
class SPSInputBuffer {};

/// Specialize to describe how to serialize/deserialize to/from the given
/// concrete type.
template <typename SPSTagT, typename ConcreteT, typename _ = void>
class SPSSerializationTraits;

/// A utility class for serializing to a blob from a variadic list.
template <typename... ArgTs> class SPSArgList;

// Empty list specialization for SPSArgList.
template <> class SPSArgList<> {};

// Non-empty list specialization for SPSArgList.
SPSArgList<SPSTagT, SPSTagTs...>;

/// SPS serialization for integral types, bool, and char.
SPSSerializationTraits<SPSTagT, SPSTagT, std::enable_if_t<std::is_same<SPSTagT, bool>::value || std::is_same<SPSTagT, char>::value || std::is_same<SPSTagT, int8_t>::value || std::is_same<SPSTagT, int16_t>::value || std::is_same<SPSTagT, int32_t>::value || std::is_same<SPSTagT, int64_t>::value || std::is_same<SPSTagT, uint8_t>::value || std::is_same<SPSTagT, uint16_t>::value || std::is_same<SPSTagT, uint32_t>::value || std::is_same<SPSTagT, uint64_t>::value>>;

// Any empty placeholder suitable as a substitute for void when deserializing
class SPSEmpty {};

/// SPS tag type for tuples.
///
/// A blob tuple should be serialized by serializing each of the elements in
/// sequence.
template <typename... SPSTagTs> class SPSTuple {};

/// SPS tag type for optionals.
///
/// SPSOptionals should be serialized as a bool with true indicating that an
/// SPSTagT value is present, and false indicating that there is no value.
/// If the boolean is true then the serialized SPSTagT will follow immediately
/// after it.
template <typename SPSTagT> class SPSOptional {};

/// SPS tag type for sequences.
///
/// SPSSequences should be serialized as a uint64_t sequence length,
/// followed by the serialization of each of the elements.
template <typename SPSElementTagT> class SPSSequence;

/// SPS tag type for strings, which are equivalent to sequences of chars.
SPSString;

/// SPS tag type for maps.
///
/// SPS maps are just sequences of (Key, Value) tuples.
SPSMap;

/// Serialization for SPSEmpty type.
template <> class SPSSerializationTraits<SPSEmpty, SPSEmpty> {};

/// Specialize this to implement 'trivial' sequence serialization for
/// a concrete sequence type.
///
/// Trivial sequence serialization uses the sequence's 'size' member to get the
/// length of the sequence, and uses a range-based for loop to iterate over the
/// elements.
///
/// Specializing this template class means that you do not need to provide a
/// specialization of SPSSerializationTraits for your type.
template <typename SPSElementTagT, typename ConcreteSequenceT>
class TrivialSPSSequenceSerialization {};

/// Specialize this to implement 'trivial' sequence deserialization for
/// a concrete sequence type.
///
/// Trivial deserialization calls a static 'reserve(SequenceT&)' method on your
/// specialization (you must implement this) to reserve space, and then calls
/// a static 'append(SequenceT&, ElementT&) method to append each of the
/// deserialized elements.
///
/// Specializing this template class means that you do not need to provide a
/// specialization of SPSSerializationTraits for your type.
template <typename SPSElementTagT, typename ConcreteSequenceT>
class TrivialSPSSequenceDeserialization {};

/// Trivial std::string -> SPSSequence<char> serialization.
template <> class TrivialSPSSequenceSerialization<char, std::string> {};

/// Trivial SPSSequence<char> -> std::string deserialization.
template <> class TrivialSPSSequenceDeserialization<char, std::string> {};

/// Trivial std::vector<T> -> SPSSequence<SPSElementTagT> serialization.
TrivialSPSSequenceSerialization<SPSElementTagT, std::vector<T>>;

/// Trivial SPSSequence<SPSElementTagT> -> std::vector<T> deserialization.
TrivialSPSSequenceDeserialization<SPSElementTagT, std::vector<T>>;

/// Trivial SmallVectorImpl<T> -> SPSSequence<char> serialization.
TrivialSPSSequenceSerialization<SPSElementTagT, SmallVectorImpl<T>>;

/// Trivial SPSSequence<SPSElementTagT> -> SmallVectorImpl<T> deserialization.
TrivialSPSSequenceDeserialization<SPSElementTagT, SmallVectorImpl<T>>;

/// Trivial SmallVectorImpl<T> -> SPSSequence<char> serialization.
TrivialSPSSequenceSerialization<SPSElementTagT, SmallVector<T, N>>;

/// Trivial SPSSequence<SPSElementTagT> -> SmallVectorImpl<T> deserialization.
TrivialSPSSequenceDeserialization<SPSElementTagT, SmallVector<T, N>>;

/// Trivial ArrayRef<T> -> SPSSequence<SPSElementTagT> serialization.
TrivialSPSSequenceSerialization<SPSElementTagT, ArrayRef<T>>;

/// Specialized SPSSequence<char> -> ArrayRef<char> serialization.
///
/// On deserialize, points directly into the input buffer.
template <> class SPSSerializationTraits<SPSSequence<char>, ArrayRef<char>> {};

/// 'Trivial' sequence serialization: Sequence is serialized as a uint64_t size
/// followed by a for-earch loop over the elements of the sequence to serialize
/// each of them.
SPSSerializationTraits<SPSSequence<SPSElementTagT>, SequenceT, std::enable_if_t<TrivialSPSSequenceSerialization<SPSElementTagT, SequenceT>::available>>;

/// SPSTuple serialization for std::tuple.
SPSSerializationTraits<SPSTuple<SPSTagTs...>, std::tuple<Ts...>>;

/// SPSTuple serialization for std::pair.
SPSSerializationTraits<SPSTuple<SPSTagT1, SPSTagT2>, std::pair<T1, T2>>;

/// SPSOptional serialization for std::optional.
SPSSerializationTraits<SPSOptional<SPSTagT>, std::optional<T>>;

/// Serialization for StringRefs.
///
/// Serialization is as for regular strings. Deserialization points directly
/// into the blob.
template <> class SPSSerializationTraits<SPSString, StringRef> {};

/// Serialization for StringMap<ValueT>s.
SPSSerializationTraits<SPSSequence<SPSTuple<SPSString, SPSValueT>>, StringMap<ValueT>>;

/// 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.
/// This makes them unsuitable for direct serialization via
/// SPSSerializationTraits, which needs to inspect values twice (once to
/// determine the amount of space to reserve, and then again to serialize).
///
/// The SPSSerializableError type is a helper that can be
/// constructed from an llvm::Error, but inspected more than once.
struct SPSSerializableError {};

/// 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 {};

inline SPSSerializableError toSPSSerializable(Error Err) {}

inline Error fromSPSSerializable(SPSSerializableError BSE) {}

template <typename T>
SPSSerializableExpected<T> toSPSSerializable(Expected<T> E) {}

template <typename T>
Expected<T> fromSPSSerializable(SPSSerializableExpected<T> BSE) {}

} // end namespace detail

/// Serialize to a SPSError from a detail::SPSSerializableError.
template <>
class SPSSerializationTraits<SPSError, detail::SPSSerializableError> {};

/// Serialize to a SPSExpected<SPSTagT> from a
/// detail::SPSSerializableExpected<T>.
SPSSerializationTraits<SPSExpected<SPSTagT>, detail::SPSSerializableExpected<T>>;

/// Serialize to a SPSExpected<SPSTagT> from a detail::SPSSerializableError.
SPSSerializationTraits<SPSExpected<SPSTagT>, detail::SPSSerializableError>;

/// Serialize to a SPSExpected<SPSTagT> from a T.
SPSSerializationTraits<SPSExpected<SPSTagT>, T>;

} // end namespace shared
} // end namespace orc
} // end namespace llvm

#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEPACKEDSERIALIZATION_H