// 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 #include #include #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 class ArrayDataView; template class AssociatedInterfacePtrInfoDataView; template class AssociatedInterfaceRequestDataView; template class InterfacePtrDataView; template class InterfaceRequestDataView; template 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(-1); // A serialized union always takes 16 bytes: // 4-byte size + 4-byte tag + 8-byte payload. const uint32_t kUnionDataSize = 16; template class Array_Data; template class Map_Data; using String_Data = Array_Data; inline size_t Align(size_t size) { return (size + 7) & ~0x7; } inline bool IsAligned(const void* ptr) { return !(reinterpret_cast(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(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(ptr); const char* p_slot = reinterpret_cast(offset); DCHECK(p_obj > p_slot); *offset = static_cast(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(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 struct Pointer { using BaseType = T; void Set(T* ptr) { EncodePointer(ptr, &offset); } const T* Get() const { return static_cast(DecodePointer(&offset)); } T* Get() { return static_cast(const_cast(DecodePointer(&offset))); } bool is_null() const { return offset == 0; } uint64_t offset; }; static_assert(sizeof(Pointer) == 8, "Bad_sizeof(Pointer)"); using GenericPointer = Pointer; 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 T FetchAndReset(T* ptr) { T temp = *ptr; *ptr = T(); return temp; } template struct IsUnionDataType { private: template static YesType Test(const typename U::MojomUnionDataType*); template static NoType Test(...); EnsureTypeIsComplete check_t_; public: static const bool value = sizeof(Test(0)) == sizeof(YesType) && !IsConst::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(static_cast(x) & static_cast(y)); } inline constexpr MojomTypeCategory operator|(MojomTypeCategory x, MojomTypeCategory y) { return static_cast(static_cast(x) | static_cast(y)); } template ::value> struct MojomTypeTraits { using Data = T; using DataAsArrayElement = Data; static const MojomTypeCategory category = MojomTypeCategory::POD; }; template struct MojomTypeTraits, false> { using Data = Array_Data::DataAsArrayElement>; using DataAsArrayElement = Pointer; static const MojomTypeCategory category = MojomTypeCategory::ARRAY; }; template struct MojomTypeTraits, false> { using Data = AssociatedInterface_Data; using DataAsArrayElement = Data; static const MojomTypeCategory category = MojomTypeCategory::ASSOCIATED_INTERFACE; }; template struct MojomTypeTraits, false> { using Data = AssociatedEndpointHandle_Data; using DataAsArrayElement = Data; static const MojomTypeCategory category = MojomTypeCategory::ASSOCIATED_INTERFACE_REQUEST; }; template <> struct MojomTypeTraits { using Data = bool; using DataAsArrayElement = Data; static const MojomTypeCategory category = MojomTypeCategory::BOOLEAN; }; template struct MojomTypeTraits { using Data = int32_t; using DataAsArrayElement = Data; static const MojomTypeCategory category = MojomTypeCategory::ENUM; }; template struct MojomTypeTraits, false> { using Data = Handle_Data; using DataAsArrayElement = Data; static const MojomTypeCategory category = MojomTypeCategory::HANDLE; }; template struct MojomTypeTraits, false> { using Data = Interface_Data; using DataAsArrayElement = Data; static const MojomTypeCategory category = MojomTypeCategory::INTERFACE; }; template struct MojomTypeTraits, false> { using Data = Handle_Data; using DataAsArrayElement = Data; static const MojomTypeCategory category = MojomTypeCategory::INTERFACE_REQUEST; }; template struct MojomTypeTraits, false> { using Data = Map_Data::DataAsArrayElement, typename MojomTypeTraits::DataAsArrayElement>; using DataAsArrayElement = Pointer; static const MojomTypeCategory category = MojomTypeCategory::MAP; }; template <> struct MojomTypeTraits { using Data = String_Data; using DataAsArrayElement = Pointer; static const MojomTypeCategory category = MojomTypeCategory::STRING; }; template struct BelongsTo { static const bool value = static_cast(MojomTypeTraits::category & categories) != 0; }; template struct EnumHashImpl { static_assert(std::is_enum::value, "Incorrect hash function."); size_t operator()(T input) const { using UnderlyingType = typename std::underlying_type::type; return std::hash()(static_cast(input)); } }; template T ConvertEnumValue(MojomType input) { T output; bool result = EnumTraits::FromMojom(input, &output); DCHECK(result); return output; } } // namespace internal } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_