blob: f51d807f5bf5d23a9f9cf0dad38e117ad1a93c71 [file] [log] [blame]
#ifndef ANDROID_PDX_RPC_ENCODING_H_
#define ANDROID_PDX_RPC_ENCODING_H_
#include <array>
#include <cstdint>
#include <cstring>
#include <map>
#include <numeric>
#include <string>
#include <tuple>
#include <unordered_map>
#include <vector>
#include <pdx/channel_handle.h>
#include <pdx/file_handle.h>
#include "array_wrapper.h"
#include "buffer_wrapper.h"
#include "string_wrapper.h"
#include "variant.h"
namespace android {
namespace pdx {
namespace rpc {
// This library uses a subset, or profile, of MessagePack (http://msgpack.org)
// to encode supported data types during serialization and to verify the
// expected data types during deserialization. One notable deviation from the
// MessagePack specification is that little-endian byte order is used for
// multi-byte numeric types to avoid unnecessary conversion on nearly all
// relevant architectures.
//
// Some data types, integers for example, support multiple encoding strategies.
// This library attempts to optimize for space based on the value of such types.
// However, during decode all valid encodings for a given type are accepted.
// Prefix byte for type encodings. This is the complete list of prefix bytes
// from the MessagePack specification, even though not all types are used by
// this library.
enum EncodingPrefix {
ENCODING_TYPE_POSITIVE_FIXINT = 0x00,
ENCODING_TYPE_POSITIVE_FIXINT_MIN = 0x00,
ENCODING_TYPE_POSITIVE_FIXINT_MAX = 0x7f,
ENCODING_TYPE_POSITIVE_FIXINT_MASK = 0x7f,
ENCODING_TYPE_FIXMAP = 0x80,
ENCODING_TYPE_FIXMAP_MIN = 0x80,
ENCODING_TYPE_FIXMAP_MAX = 0x8f,
ENCODING_TYPE_FIXMAP_MASK = 0x0f,
ENCODING_TYPE_FIXARRAY = 0x90,
ENCODING_TYPE_FIXARRAY_MIN = 0x90,
ENCODING_TYPE_FIXARRAY_MAX = 0x9f,
ENCODING_TYPE_FIXARRAY_MASK = 0x0f,
ENCODING_TYPE_FIXSTR = 0xa0,
ENCODING_TYPE_FIXSTR_MIN = 0xa0,
ENCODING_TYPE_FIXSTR_MAX = 0xbf,
ENCODING_TYPE_FIXSTR_MASK = 0x1f,
ENCODING_TYPE_NIL = 0xc0,
ENCODING_TYPE_RESERVED = 0xc1,
ENCODING_TYPE_FALSE = 0xc2,
ENCODING_TYPE_TRUE = 0xc3,
ENCODING_TYPE_BIN8 = 0xc4,
ENCODING_TYPE_BIN16 = 0xc5,
ENCODING_TYPE_BIN32 = 0xc6,
ENCODING_TYPE_EXT8 = 0xc7,
ENCODING_TYPE_EXT16 = 0xc8,
ENCODING_TYPE_EXT32 = 0xc9,
ENCODING_TYPE_FLOAT32 = 0xca,
ENCODING_TYPE_FLOAT64 = 0xcb,
ENCODING_TYPE_UINT8 = 0xcc,
ENCODING_TYPE_UINT16 = 0xcd,
ENCODING_TYPE_UINT32 = 0xce,
ENCODING_TYPE_UINT64 = 0xcf,
ENCODING_TYPE_INT8 = 0xd0,
ENCODING_TYPE_INT16 = 0xd1,
ENCODING_TYPE_INT32 = 0xd2,
ENCODING_TYPE_INT64 = 0xd3,
ENCODING_TYPE_FIXEXT1 = 0xd4,
ENCODING_TYPE_FIXEXT2 = 0xd5,
ENCODING_TYPE_FIXEXT4 = 0xd6,
ENCODING_TYPE_FIXEXT8 = 0xd7,
ENCODING_TYPE_FIXEXT16 = 0xd8,
ENCODING_TYPE_STR8 = 0xd9,
ENCODING_TYPE_STR16 = 0xda,
ENCODING_TYPE_STR32 = 0xdb,
ENCODING_TYPE_ARRAY16 = 0xdc,
ENCODING_TYPE_ARRAY32 = 0xdd,
ENCODING_TYPE_MAP16 = 0xde,
ENCODING_TYPE_MAP32 = 0xdf,
ENCODING_TYPE_NEGATIVE_FIXINT = 0xe0,
ENCODING_TYPE_NEGATIVE_FIXINT_MIN = 0xe0,
ENCODING_TYPE_NEGATIVE_FIXINT_MAX = 0xff,
};
// Base encoding classes grouping multi-strategy encodings.
enum EncodingClass {
ENCODING_CLASS_BOOL,
ENCODING_CLASS_NIL,
ENCODING_CLASS_INT,
ENCODING_CLASS_UINT,
ENCODING_CLASS_FLOAT,
ENCODING_CLASS_ARRAY,
ENCODING_CLASS_MAP,
ENCODING_CLASS_STRING,
ENCODING_CLASS_BINARY,
ENCODING_CLASS_EXTENSION,
};
// Encoding prefixes are unsigned bytes.
typedef std::uint8_t EncodingType;
// Extension encoding types defined by this library.
enum EncodingExtType : int8_t {
ENCODING_EXT_TYPE_FILE_DESCRIPTOR,
ENCODING_EXT_TYPE_CHANNEL_HANDLE,
};
// Encoding predicates. Determines whether the given encoding is of a specific
// type.
inline constexpr bool IsFixintEncoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX:
case ENCODING_TYPE_NEGATIVE_FIXINT_MIN ... ENCODING_TYPE_NEGATIVE_FIXINT_MAX:
return true;
default:
return false;
}
}
inline constexpr bool IsUnsignedFixintEncoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX:
return true;
default:
return false;
}
}
inline constexpr bool IsInt8Encoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX:
case ENCODING_TYPE_NEGATIVE_FIXINT_MIN ... ENCODING_TYPE_NEGATIVE_FIXINT_MAX:
case ENCODING_TYPE_INT8:
return true;
default:
return false;
}
}
inline constexpr bool IsUInt8Encoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX:
case ENCODING_TYPE_UINT8:
return true;
default:
return false;
}
}
inline constexpr bool IsInt16Encoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX:
case ENCODING_TYPE_NEGATIVE_FIXINT_MIN ... ENCODING_TYPE_NEGATIVE_FIXINT_MAX:
case ENCODING_TYPE_INT8:
case ENCODING_TYPE_INT16:
return true;
default:
return false;
}
}
inline constexpr bool IsUInt16Encoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX:
case ENCODING_TYPE_UINT8:
case ENCODING_TYPE_UINT16:
return true;
default:
return false;
}
}
inline constexpr bool IsInt32Encoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX:
case ENCODING_TYPE_NEGATIVE_FIXINT_MIN ... ENCODING_TYPE_NEGATIVE_FIXINT_MAX:
case ENCODING_TYPE_INT8:
case ENCODING_TYPE_INT16:
case ENCODING_TYPE_INT32:
return true;
default:
return false;
}
}
inline constexpr bool IsUInt32Encoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX:
case ENCODING_TYPE_UINT8:
case ENCODING_TYPE_UINT16:
case ENCODING_TYPE_UINT32:
return true;
default:
return false;
}
}
inline constexpr bool IsInt64Encoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX:
case ENCODING_TYPE_NEGATIVE_FIXINT_MIN ... ENCODING_TYPE_NEGATIVE_FIXINT_MAX:
case ENCODING_TYPE_INT8:
case ENCODING_TYPE_INT16:
case ENCODING_TYPE_INT32:
case ENCODING_TYPE_INT64:
return true;
default:
return false;
}
}
inline constexpr bool IsUInt64Encoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX:
case ENCODING_TYPE_UINT8:
case ENCODING_TYPE_UINT16:
case ENCODING_TYPE_UINT32:
case ENCODING_TYPE_UINT64:
return true;
default:
return false;
}
}
inline constexpr bool IsFixmapEncoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_FIXMAP_MIN ... ENCODING_TYPE_FIXMAP_MAX:
return true;
default:
return false;
}
}
inline constexpr bool IsFixarrayEncoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_FIXARRAY_MIN ... ENCODING_TYPE_FIXARRAY_MAX:
return true;
default:
return false;
}
}
inline constexpr bool IsFixstrEncoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_FIXSTR_MIN ... ENCODING_TYPE_FIXSTR_MAX:
return true;
default:
return false;
}
}
inline constexpr bool IsFixextEncoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_FIXEXT1:
case ENCODING_TYPE_FIXEXT2:
case ENCODING_TYPE_FIXEXT4:
case ENCODING_TYPE_FIXEXT8:
case ENCODING_TYPE_FIXEXT16:
return true;
default:
return false;
}
}
inline constexpr bool IsFloat32Encoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_FLOAT32:
return true;
default:
return false;
}
}
inline constexpr bool IsFloat64Encoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_FLOAT32:
case ENCODING_TYPE_FLOAT64:
return true;
default:
return false;
}
}
inline constexpr bool IsBoolEncoding(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_FALSE:
case ENCODING_TYPE_TRUE:
return true;
default:
return false;
}
}
inline constexpr std::size_t GetFixstrSize(EncodingType encoding) {
return encoding & ENCODING_TYPE_FIXSTR_MASK;
}
inline constexpr std::size_t GetFixarraySize(EncodingType encoding) {
return encoding & ENCODING_TYPE_FIXARRAY_MASK;
}
inline constexpr std::size_t GetFixmapSize(EncodingType encoding) {
return encoding & ENCODING_TYPE_FIXMAP_MASK;
}
inline constexpr std::size_t GetFixextSize(EncodingType encoding) {
switch (encoding) {
case ENCODING_TYPE_FIXEXT1:
return 1;
case ENCODING_TYPE_FIXEXT2:
return 2;
case ENCODING_TYPE_FIXEXT4:
return 4;
case ENCODING_TYPE_FIXEXT8:
return 8;
case ENCODING_TYPE_FIXEXT16:
return 16;
default:
return 0; // Invalid fixext size.
}
}
// Gets the size of the encoding in bytes, not including external payload data.
inline constexpr std::size_t GetEncodingSize(EncodingType encoding) {
switch (encoding) {
// Encoding is fully contained within the type value.
case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX:
case ENCODING_TYPE_NEGATIVE_FIXINT_MIN ... ENCODING_TYPE_NEGATIVE_FIXINT_MAX:
case ENCODING_TYPE_FIXMAP_MIN ... ENCODING_TYPE_FIXMAP_MAX:
case ENCODING_TYPE_FIXARRAY_MIN ... ENCODING_TYPE_FIXARRAY_MAX:
case ENCODING_TYPE_FIXSTR_MIN ... ENCODING_TYPE_FIXSTR_MAX:
case ENCODING_TYPE_NIL:
case ENCODING_TYPE_RESERVED:
case ENCODING_TYPE_FALSE:
case ENCODING_TYPE_TRUE:
return 1;
// Encoding type followed by one-byte size or immediate value.
case ENCODING_TYPE_BIN8:
case ENCODING_TYPE_EXT8:
case ENCODING_TYPE_UINT8:
case ENCODING_TYPE_INT8:
case ENCODING_TYPE_STR8:
// Encoding type followed by one-byte extension type.
case ENCODING_TYPE_FIXEXT1:
case ENCODING_TYPE_FIXEXT2:
case ENCODING_TYPE_FIXEXT4:
case ENCODING_TYPE_FIXEXT8:
case ENCODING_TYPE_FIXEXT16:
return 2;
// Encoding type followed by two-byte size or immediate value.
case ENCODING_TYPE_BIN16:
case ENCODING_TYPE_EXT16:
case ENCODING_TYPE_UINT16:
case ENCODING_TYPE_INT16:
case ENCODING_TYPE_STR16:
case ENCODING_TYPE_ARRAY16:
case ENCODING_TYPE_MAP16:
return 3;
// Encoding type followed by four-byte size or immediate value.
case ENCODING_TYPE_BIN32:
case ENCODING_TYPE_EXT32:
case ENCODING_TYPE_FLOAT32:
case ENCODING_TYPE_UINT32:
case ENCODING_TYPE_INT32:
case ENCODING_TYPE_STR32:
case ENCODING_TYPE_ARRAY32:
case ENCODING_TYPE_MAP32:
return 5;
// Encoding type followed by eight-byte immediate value.
case ENCODING_TYPE_FLOAT64:
case ENCODING_TYPE_UINT64:
case ENCODING_TYPE_INT64:
return 9;
default:
return 0;
}
}
// Encoding for standard types. Each supported data type has an associated
// encoding or set of encodings. These functions determine the MessagePack
// encoding based on the data type, value, and size of their arguments.
inline constexpr EncodingType EncodeArrayType(std::size_t size) {
if (size < (1U << 4))
return ENCODING_TYPE_FIXARRAY | (size & ENCODING_TYPE_FIXARRAY_MASK);
else if (size < (1U << 16))
return ENCODING_TYPE_ARRAY16;
else
return ENCODING_TYPE_ARRAY32;
}
inline constexpr EncodingType EncodeMapType(std::size_t size) {
if (size < (1U << 4))
return ENCODING_TYPE_FIXMAP | (size & ENCODING_TYPE_FIXMAP_MASK);
else if (size < (1U << 16))
return ENCODING_TYPE_MAP16;
else
return ENCODING_TYPE_MAP32;
}
inline constexpr EncodingType EncodeStringType(std::size_t size) {
if (size < (1U << 5))
return ENCODING_TYPE_FIXSTR | (size & ENCODING_TYPE_FIXSTR_MASK);
else if (size < (1U << 8))
return ENCODING_TYPE_STR8;
else if (size < (1U << 16))
return ENCODING_TYPE_STR16;
else
return ENCODING_TYPE_STR32;
}
inline constexpr EncodingType EncodeBinType(std::size_t size) {
if (size < (1U << 8))
return ENCODING_TYPE_BIN8;
else if (size < (1U << 16))
return ENCODING_TYPE_BIN16;
else
return ENCODING_TYPE_BIN32;
}
inline EncodingType EncodeType(const EmptyVariant& /*empty*/) {
return ENCODING_TYPE_NIL;
}
// Variant is encoded as a single-element map, with the type index as the key.
template <typename... Types>
inline EncodingType EncodeType(const Variant<Types...>& /*variant*/) {
return EncodeMapType(1);
}
template <typename T>
inline constexpr EncodingType EncodeType(const StringWrapper<T>& value) {
return EncodeStringType(value.length());
}
inline constexpr EncodingType EncodeType(const std::string& value) {
return EncodeStringType(value.length());
}
template <typename T, std::size_t Size>
inline constexpr EncodingType EncodeType(const std::array<T, Size>& /*value*/) {
return EncodeArrayType(Size);
}
template <typename T>
inline constexpr EncodingType EncodeType(const ArrayWrapper<T>& value) {
return EncodeArrayType(value.size());
}
template <typename T, typename Allocator>
inline constexpr EncodingType EncodeType(
const std::vector<T, Allocator>& value) {
return EncodeArrayType(value.size());
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline constexpr EncodingType EncodeType(
const std::map<Key, T, Compare, Allocator>& value) {
return EncodeMapType(value.size());
}
template <typename Key, typename T, typename Hash, typename KeyEqual,
typename Allocator>
inline constexpr EncodingType EncodeType(
const std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& value) {
return EncodeMapType(value.size());
}
template <typename T>
inline constexpr EncodingType EncodeType(const BufferWrapper<T>& value) {
// BIN size is in bytes.
return EncodeBinType(value.size() *
sizeof(typename BufferWrapper<T>::value_type));
}
template <typename T, typename U>
inline constexpr EncodingType EncodeType(const std::pair<T, U>& /*value*/) {
return EncodeArrayType(2);
}
template <typename... T>
inline constexpr EncodingType EncodeType(const std::tuple<T...>& /*value*/) {
return EncodeArrayType(sizeof...(T));
}
// FileHandle is encoded as a FIXEXT2 with a type code for "FileDescriptor"
// and a signed 16-bit index into the pushed fd array. Empty file descriptor
// have an array index of -1.
template <FileHandleMode Mode>
inline constexpr EncodingType EncodeType(const FileHandle<Mode>& /*fd*/) {
return ENCODING_TYPE_FIXEXT2;
}
// ChannelHandle is encoded as a FIXEXT4 with a type of
// ENCODING_EXT_TYPE_CHANNEL_HANDLE and a signed 32-bit value representing
// a client channel in a remote process. Empty handle has a value of -1.
template <ChannelHandleMode Mode>
inline constexpr EncodingType EncodeType(
const ChannelHandle<Mode>& /*handle*/) {
return ENCODING_TYPE_FIXEXT4;
}
inline constexpr EncodingType EncodeType(const bool& value) {
return value ? ENCODING_TYPE_TRUE : ENCODING_TYPE_FALSE;
}
// Type 'char' is a little bit special in that it is distinct from 'signed char'
// and 'unsigned char'. Treating it as an unsigned 8-bit value is safe for
// encoding purposes and nicely handles 7-bit ASCII encodings as FIXINT.
inline constexpr EncodingType EncodeType(const char& value) {
if (value < static_cast<char>(1 << 7))
return value;
else
return ENCODING_TYPE_UINT8;
}
inline constexpr EncodingType EncodeType(const uint8_t& value) {
if (value < (1U << 7))
return value;
else
return ENCODING_TYPE_UINT8;
}
inline constexpr EncodingType EncodeType(const int8_t& value) {
if (value >= -32)
return value;
else
return ENCODING_TYPE_INT8;
}
inline constexpr EncodingType EncodeType(const uint16_t& value) {
if (value < (1U << 7))
return static_cast<EncodingType>(value);
else if (value < (1U << 8))
return ENCODING_TYPE_UINT8;
else
return ENCODING_TYPE_UINT16;
}
inline constexpr EncodingType EncodeType(const int16_t& value) {
if (value >= -32 && value <= 127)
return static_cast<EncodingType>(value);
else if (value >= -128 && value <= 127)
return ENCODING_TYPE_INT8;
else
return ENCODING_TYPE_INT16;
}
inline constexpr EncodingType EncodeType(const uint32_t& value) {
if (value < (1U << 7))
return static_cast<EncodingType>(value);
else if (value < (1U << 8))
return ENCODING_TYPE_UINT8;
else if (value < (1U << 16))
return ENCODING_TYPE_UINT16;
else
return ENCODING_TYPE_UINT32;
}
inline constexpr EncodingType EncodeType(const int32_t& value) {
if (value >= -32 && value <= 127)
return static_cast<EncodingType>(value);
else if (value >= -128 && value <= 127)
return ENCODING_TYPE_INT8;
else if (value >= -32768 && value <= 32767)
return ENCODING_TYPE_INT16;
else
return ENCODING_TYPE_INT32;
}
inline constexpr EncodingType EncodeType(const uint64_t& value) {
if (value < (1ULL << 7))
return static_cast<EncodingType>(value);
else if (value < (1ULL << 8))
return ENCODING_TYPE_UINT8;
else if (value < (1ULL << 16))
return ENCODING_TYPE_UINT16;
else if (value < (1ULL << 32))
return ENCODING_TYPE_UINT32;
else
return ENCODING_TYPE_UINT64;
}
inline constexpr EncodingType EncodeType(const int64_t& value) {
if (value >= -32 && value <= 127)
return static_cast<EncodingType>(value);
else if (value >= -128 && value <= 127) // Effectively [-128, -32).
return ENCODING_TYPE_INT8;
else if (value >= -32768 && value <= 32767)
return ENCODING_TYPE_INT16;
else if (value >= -2147483648 && value <= 2147483647)
return ENCODING_TYPE_INT32;
else
return ENCODING_TYPE_INT64;
}
inline constexpr EncodingType EncodeType(const float& /*value*/) {
return ENCODING_TYPE_FLOAT32;
}
inline constexpr EncodingType EncodeType(const double& /*value*/) {
return ENCODING_TYPE_FLOAT64;
}
} // namespace rpc
} // namespace pdx
} // namespace android
#endif // ANDROID_PDX_RPC_ENCODING_H_