334 lines
8.7 KiB
C++
334 lines
8.7 KiB
C++
// Copyright 2013 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_
|
|
#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <functional>
|
|
#include <type_traits>
|
|
|
|
#include "mojo/public/cpp/bindings/enum_traits.h"
|
|
#include "mojo/public/cpp/bindings/interface_id.h"
|
|
#include "mojo/public/cpp/bindings/lib/template_util.h"
|
|
#include "mojo/public/cpp/system/core.h"
|
|
|
|
namespace mojo {
|
|
|
|
template <typename T>
|
|
class ArrayDataView;
|
|
|
|
template <typename T>
|
|
class AssociatedInterfacePtrInfoDataView;
|
|
|
|
template <typename T>
|
|
class AssociatedInterfaceRequestDataView;
|
|
|
|
template <typename T>
|
|
class InterfacePtrDataView;
|
|
|
|
template <typename T>
|
|
class InterfaceRequestDataView;
|
|
|
|
template <typename K, typename V>
|
|
class MapDataView;
|
|
|
|
class StringDataView;
|
|
|
|
namespace internal {
|
|
|
|
// Please note that this is a different value than |mojo::kInvalidHandleValue|,
|
|
// which is the "decoded" invalid handle.
|
|
const uint32_t kEncodedInvalidHandleValue = static_cast<uint32_t>(-1);
|
|
|
|
// A serialized union always takes 16 bytes:
|
|
// 4-byte size + 4-byte tag + 8-byte payload.
|
|
const uint32_t kUnionDataSize = 16;
|
|
|
|
template <typename T>
|
|
class Array_Data;
|
|
|
|
template <typename K, typename V>
|
|
class Map_Data;
|
|
|
|
using String_Data = Array_Data<char>;
|
|
|
|
inline size_t Align(size_t size) {
|
|
return (size + 7) & ~0x7;
|
|
}
|
|
|
|
inline bool IsAligned(const void* ptr) {
|
|
return !(reinterpret_cast<uintptr_t>(ptr) & 0x7);
|
|
}
|
|
|
|
// Pointers are encoded as relative offsets. The offsets are relative to the
|
|
// address of where the offset value is stored, such that the pointer may be
|
|
// recovered with the expression:
|
|
//
|
|
// ptr = reinterpret_cast<char*>(offset) + *offset
|
|
//
|
|
// A null pointer is encoded as an offset value of 0.
|
|
//
|
|
inline void EncodePointer(const void* ptr, uint64_t* offset) {
|
|
if (!ptr) {
|
|
*offset = 0;
|
|
return;
|
|
}
|
|
|
|
const char* p_obj = reinterpret_cast<const char*>(ptr);
|
|
const char* p_slot = reinterpret_cast<const char*>(offset);
|
|
DCHECK(p_obj > p_slot);
|
|
|
|
*offset = static_cast<uint64_t>(p_obj - p_slot);
|
|
}
|
|
|
|
// Note: This function doesn't validate the encoded pointer value.
|
|
inline const void* DecodePointer(const uint64_t* offset) {
|
|
if (!*offset)
|
|
return nullptr;
|
|
return reinterpret_cast<const char*>(offset) + *offset;
|
|
}
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
struct StructHeader {
|
|
uint32_t num_bytes;
|
|
uint32_t version;
|
|
};
|
|
static_assert(sizeof(StructHeader) == 8, "Bad sizeof(StructHeader)");
|
|
|
|
struct ArrayHeader {
|
|
uint32_t num_bytes;
|
|
uint32_t num_elements;
|
|
};
|
|
static_assert(sizeof(ArrayHeader) == 8, "Bad_sizeof(ArrayHeader)");
|
|
|
|
template <typename T>
|
|
struct Pointer {
|
|
using BaseType = T;
|
|
|
|
void Set(T* ptr) { EncodePointer(ptr, &offset); }
|
|
const T* Get() const { return static_cast<const T*>(DecodePointer(&offset)); }
|
|
T* Get() {
|
|
return static_cast<T*>(const_cast<void*>(DecodePointer(&offset)));
|
|
}
|
|
|
|
bool is_null() const { return offset == 0; }
|
|
|
|
uint64_t offset;
|
|
};
|
|
static_assert(sizeof(Pointer<char>) == 8, "Bad_sizeof(Pointer)");
|
|
|
|
using GenericPointer = Pointer<void>;
|
|
|
|
struct Handle_Data {
|
|
Handle_Data() = default;
|
|
explicit Handle_Data(uint32_t value) : value(value) {}
|
|
|
|
bool is_valid() const { return value != kEncodedInvalidHandleValue; }
|
|
|
|
uint32_t value;
|
|
};
|
|
static_assert(sizeof(Handle_Data) == 4, "Bad_sizeof(Handle_Data)");
|
|
|
|
struct Interface_Data {
|
|
Handle_Data handle;
|
|
uint32_t version;
|
|
};
|
|
static_assert(sizeof(Interface_Data) == 8, "Bad_sizeof(Interface_Data)");
|
|
|
|
struct AssociatedEndpointHandle_Data {
|
|
AssociatedEndpointHandle_Data() = default;
|
|
explicit AssociatedEndpointHandle_Data(uint32_t value) : value(value) {}
|
|
|
|
bool is_valid() const { return value != kEncodedInvalidHandleValue; }
|
|
|
|
uint32_t value;
|
|
};
|
|
static_assert(sizeof(AssociatedEndpointHandle_Data) == 4,
|
|
"Bad_sizeof(AssociatedEndpointHandle_Data)");
|
|
|
|
struct AssociatedInterface_Data {
|
|
AssociatedEndpointHandle_Data handle;
|
|
uint32_t version;
|
|
};
|
|
static_assert(sizeof(AssociatedInterface_Data) == 8,
|
|
"Bad_sizeof(AssociatedInterface_Data)");
|
|
|
|
#pragma pack(pop)
|
|
|
|
template <typename T>
|
|
T FetchAndReset(T* ptr) {
|
|
T temp = *ptr;
|
|
*ptr = T();
|
|
return temp;
|
|
}
|
|
|
|
template <typename T>
|
|
struct IsUnionDataType {
|
|
private:
|
|
template <typename U>
|
|
static YesType Test(const typename U::MojomUnionDataType*);
|
|
|
|
template <typename U>
|
|
static NoType Test(...);
|
|
|
|
EnsureTypeIsComplete<T> check_t_;
|
|
|
|
public:
|
|
static const bool value =
|
|
sizeof(Test<T>(0)) == sizeof(YesType) && !IsConst<T>::value;
|
|
};
|
|
|
|
enum class MojomTypeCategory : uint32_t {
|
|
ARRAY = 1 << 0,
|
|
ASSOCIATED_INTERFACE = 1 << 1,
|
|
ASSOCIATED_INTERFACE_REQUEST = 1 << 2,
|
|
BOOLEAN = 1 << 3,
|
|
ENUM = 1 << 4,
|
|
HANDLE = 1 << 5,
|
|
INTERFACE = 1 << 6,
|
|
INTERFACE_REQUEST = 1 << 7,
|
|
MAP = 1 << 8,
|
|
// POD except boolean and enum.
|
|
POD = 1 << 9,
|
|
STRING = 1 << 10,
|
|
STRUCT = 1 << 11,
|
|
UNION = 1 << 12
|
|
};
|
|
|
|
inline constexpr MojomTypeCategory operator&(MojomTypeCategory x,
|
|
MojomTypeCategory y) {
|
|
return static_cast<MojomTypeCategory>(static_cast<uint32_t>(x) &
|
|
static_cast<uint32_t>(y));
|
|
}
|
|
|
|
inline constexpr MojomTypeCategory operator|(MojomTypeCategory x,
|
|
MojomTypeCategory y) {
|
|
return static_cast<MojomTypeCategory>(static_cast<uint32_t>(x) |
|
|
static_cast<uint32_t>(y));
|
|
}
|
|
|
|
template <typename T, bool is_enum = std::is_enum<T>::value>
|
|
struct MojomTypeTraits {
|
|
using Data = T;
|
|
using DataAsArrayElement = Data;
|
|
|
|
static const MojomTypeCategory category = MojomTypeCategory::POD;
|
|
};
|
|
|
|
template <typename T>
|
|
struct MojomTypeTraits<ArrayDataView<T>, false> {
|
|
using Data = Array_Data<typename MojomTypeTraits<T>::DataAsArrayElement>;
|
|
using DataAsArrayElement = Pointer<Data>;
|
|
|
|
static const MojomTypeCategory category = MojomTypeCategory::ARRAY;
|
|
};
|
|
|
|
template <typename T>
|
|
struct MojomTypeTraits<AssociatedInterfacePtrInfoDataView<T>, false> {
|
|
using Data = AssociatedInterface_Data;
|
|
using DataAsArrayElement = Data;
|
|
|
|
static const MojomTypeCategory category =
|
|
MojomTypeCategory::ASSOCIATED_INTERFACE;
|
|
};
|
|
|
|
template <typename T>
|
|
struct MojomTypeTraits<AssociatedInterfaceRequestDataView<T>, false> {
|
|
using Data = AssociatedEndpointHandle_Data;
|
|
using DataAsArrayElement = Data;
|
|
|
|
static const MojomTypeCategory category =
|
|
MojomTypeCategory::ASSOCIATED_INTERFACE_REQUEST;
|
|
};
|
|
|
|
template <>
|
|
struct MojomTypeTraits<bool, false> {
|
|
using Data = bool;
|
|
using DataAsArrayElement = Data;
|
|
|
|
static const MojomTypeCategory category = MojomTypeCategory::BOOLEAN;
|
|
};
|
|
|
|
template <typename T>
|
|
struct MojomTypeTraits<T, true> {
|
|
using Data = int32_t;
|
|
using DataAsArrayElement = Data;
|
|
|
|
static const MojomTypeCategory category = MojomTypeCategory::ENUM;
|
|
};
|
|
|
|
template <typename T>
|
|
struct MojomTypeTraits<ScopedHandleBase<T>, false> {
|
|
using Data = Handle_Data;
|
|
using DataAsArrayElement = Data;
|
|
|
|
static const MojomTypeCategory category = MojomTypeCategory::HANDLE;
|
|
};
|
|
|
|
template <typename T>
|
|
struct MojomTypeTraits<InterfacePtrDataView<T>, false> {
|
|
using Data = Interface_Data;
|
|
using DataAsArrayElement = Data;
|
|
|
|
static const MojomTypeCategory category = MojomTypeCategory::INTERFACE;
|
|
};
|
|
|
|
template <typename T>
|
|
struct MojomTypeTraits<InterfaceRequestDataView<T>, false> {
|
|
using Data = Handle_Data;
|
|
using DataAsArrayElement = Data;
|
|
|
|
static const MojomTypeCategory category =
|
|
MojomTypeCategory::INTERFACE_REQUEST;
|
|
};
|
|
|
|
template <typename K, typename V>
|
|
struct MojomTypeTraits<MapDataView<K, V>, false> {
|
|
using Data = Map_Data<typename MojomTypeTraits<K>::DataAsArrayElement,
|
|
typename MojomTypeTraits<V>::DataAsArrayElement>;
|
|
using DataAsArrayElement = Pointer<Data>;
|
|
|
|
static const MojomTypeCategory category = MojomTypeCategory::MAP;
|
|
};
|
|
|
|
template <>
|
|
struct MojomTypeTraits<StringDataView, false> {
|
|
using Data = String_Data;
|
|
using DataAsArrayElement = Pointer<Data>;
|
|
|
|
static const MojomTypeCategory category = MojomTypeCategory::STRING;
|
|
};
|
|
|
|
template <typename T, MojomTypeCategory categories>
|
|
struct BelongsTo {
|
|
static const bool value =
|
|
static_cast<uint32_t>(MojomTypeTraits<T>::category & categories) != 0;
|
|
};
|
|
|
|
template <typename T>
|
|
struct EnumHashImpl {
|
|
static_assert(std::is_enum<T>::value, "Incorrect hash function.");
|
|
|
|
size_t operator()(T input) const {
|
|
using UnderlyingType = typename std::underlying_type<T>::type;
|
|
return std::hash<UnderlyingType>()(static_cast<UnderlyingType>(input));
|
|
}
|
|
};
|
|
|
|
template <typename MojomType, typename T>
|
|
T ConvertEnumValue(MojomType input) {
|
|
T output;
|
|
bool result = EnumTraits<MojomType, T>::FromMojom(input, &output);
|
|
DCHECK(result);
|
|
return output;
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace mojo
|
|
|
|
#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_
|