// 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_