1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_ 6#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_ 7 8#include <stdint.h> 9 10#include <functional> 11 12#include "base/template_util.h" 13#include "mojo/public/cpp/bindings/interface_id.h" 14#include "mojo/public/cpp/bindings/lib/template_util.h" 15#include "mojo/public/cpp/system/core.h" 16 17namespace mojo { 18 19template <typename T> 20class Array; 21 22template <typename T> 23class AssociatedInterfacePtrInfo; 24 25template <typename T> 26class AssociatedInterfaceRequest; 27 28template <typename T> 29class InterfacePtr; 30 31template <typename T> 32class InterfaceRequest; 33 34template <typename K, typename V> 35class Map; 36 37class String; 38 39template <typename T> 40class StructPtr; 41 42template <typename T> 43class InlinedStructPtr; 44 45namespace internal { 46 47// Please note that this is a different value than |mojo::kInvalidHandleValue|, 48// which is the "decoded" invalid handle. 49const uint32_t kEncodedInvalidHandleValue = static_cast<uint32_t>(-1); 50 51// A serialized union always takes 16 bytes: 52// 4-byte size + 4-byte tag + 8-byte payload. 53const uint32_t kUnionDataSize = 16; 54 55template <typename T> 56class Array_Data; 57 58template <typename K, typename V> 59class Map_Data; 60 61using String_Data = Array_Data<char>; 62 63size_t Align(size_t size); 64char* AlignPointer(char* ptr); 65 66bool IsAligned(const void* ptr); 67 68// Pointers are encoded as relative offsets. The offsets are relative to the 69// address of where the offset value is stored, such that the pointer may be 70// recovered with the expression: 71// 72// ptr = reinterpret_cast<char*>(offset) + *offset 73// 74// A null pointer is encoded as an offset value of 0. 75// 76void EncodePointer(const void* ptr, uint64_t* offset); 77// Note: This function doesn't validate the encoded pointer value. 78inline const void* DecodePointer(const uint64_t* offset) { 79 if (!*offset) 80 return nullptr; 81 return reinterpret_cast<const char*>(offset) + *offset; 82} 83 84#pragma pack(push, 1) 85 86struct StructHeader { 87 uint32_t num_bytes; 88 uint32_t version; 89}; 90static_assert(sizeof(StructHeader) == 8, "Bad sizeof(StructHeader)"); 91 92struct ArrayHeader { 93 uint32_t num_bytes; 94 uint32_t num_elements; 95}; 96static_assert(sizeof(ArrayHeader) == 8, "Bad_sizeof(ArrayHeader)"); 97 98template <typename T> 99struct Pointer { 100 using BaseType = T; 101 102 void Set(T* ptr) { EncodePointer(ptr, &offset); } 103 const T* Get() const { return static_cast<const T*>(DecodePointer(&offset)); } 104 T* Get() { 105 return static_cast<T*>(const_cast<void*>(DecodePointer(&offset))); 106 } 107 108 bool is_null() const { return offset == 0; } 109 110 uint64_t offset; 111}; 112static_assert(sizeof(Pointer<char>) == 8, "Bad_sizeof(Pointer)"); 113 114struct Handle_Data { 115 Handle_Data() = default; 116 explicit Handle_Data(uint32_t value) : value(value) {} 117 118 bool is_valid() const { return value != kEncodedInvalidHandleValue; } 119 120 uint32_t value; 121}; 122static_assert(sizeof(Handle_Data) == 4, "Bad_sizeof(Handle_Data)"); 123 124struct Interface_Data { 125 Handle_Data handle; 126 uint32_t version; 127}; 128static_assert(sizeof(Interface_Data) == 8, "Bad_sizeof(Interface_Data)"); 129 130struct AssociatedInterface_Data { 131 InterfaceId interface_id; 132 uint32_t version; 133}; 134static_assert(sizeof(AssociatedInterface_Data) == 8, 135 "Bad_sizeof(AssociatedInterface_Data)"); 136 137struct AssociatedInterfaceRequest_Data { 138 InterfaceId interface_id; 139}; 140static_assert(sizeof(AssociatedInterfaceRequest_Data) == 4, 141 "Bad_sizeof(AssociatedInterfaceRequest_Data)"); 142 143#pragma pack(pop) 144 145template <typename T> 146T FetchAndReset(T* ptr) { 147 T temp = *ptr; 148 *ptr = T(); 149 return temp; 150} 151 152template <typename T> 153struct IsUnionDataType { 154 private: 155 template <typename U> 156 static YesType Test(const typename U::MojomUnionDataType*); 157 158 template <typename U> 159 static NoType Test(...); 160 161 EnsureTypeIsComplete<T> check_t_; 162 163 public: 164 static const bool value = 165 sizeof(Test<T>(0)) == sizeof(YesType) && !IsConst<T>::value; 166}; 167 168enum class MojomTypeCategory : uint32_t { 169 ARRAY = 1 << 0, 170 ASSOCIATED_INTERFACE = 1 << 1, 171 ASSOCIATED_INTERFACE_REQUEST = 1 << 2, 172 BOOLEAN = 1 << 3, 173 ENUM = 1 << 4, 174 HANDLE = 1 << 5, 175 INTERFACE = 1 << 6, 176 INTERFACE_REQUEST = 1 << 7, 177 MAP = 1 << 8, 178 // POD except boolean and enum. 179 POD = 1 << 9, 180 STRING = 1 << 10, 181 STRUCT = 1 << 11, 182 UNION = 1 << 12 183}; 184 185inline constexpr MojomTypeCategory operator&(MojomTypeCategory x, 186 MojomTypeCategory y) { 187 return static_cast<MojomTypeCategory>(static_cast<uint32_t>(x) & 188 static_cast<uint32_t>(y)); 189} 190 191inline constexpr MojomTypeCategory operator|(MojomTypeCategory x, 192 MojomTypeCategory y) { 193 return static_cast<MojomTypeCategory>(static_cast<uint32_t>(x) | 194 static_cast<uint32_t>(y)); 195} 196 197template <typename T, bool is_enum = std::is_enum<T>::value> 198struct MojomTypeTraits { 199 using Data = T; 200 using DataAsArrayElement = Data; 201 202 static const MojomTypeCategory category = MojomTypeCategory::POD; 203}; 204 205template <typename T> 206struct MojomTypeTraits<Array<T>, false> { 207 using Data = Array_Data<typename MojomTypeTraits<T>::DataAsArrayElement>; 208 using DataAsArrayElement = Pointer<Data>; 209 210 static const MojomTypeCategory category = MojomTypeCategory::ARRAY; 211}; 212 213template <typename T> 214struct MojomTypeTraits<AssociatedInterfacePtrInfo<T>, false> { 215 using Data = AssociatedInterface_Data; 216 using DataAsArrayElement = Data; 217 218 static const MojomTypeCategory category = 219 MojomTypeCategory::ASSOCIATED_INTERFACE; 220}; 221 222template <typename T> 223struct MojomTypeTraits<AssociatedInterfaceRequest<T>, false> { 224 using Data = AssociatedInterfaceRequest_Data; 225 using DataAsArrayElement = Data; 226 227 static const MojomTypeCategory category = 228 MojomTypeCategory::ASSOCIATED_INTERFACE_REQUEST; 229}; 230 231template <> 232struct MojomTypeTraits<bool, false> { 233 using Data = bool; 234 using DataAsArrayElement = Data; 235 236 static const MojomTypeCategory category = MojomTypeCategory::BOOLEAN; 237}; 238 239template <typename T> 240struct MojomTypeTraits<T, true> { 241 using Data = int32_t; 242 using DataAsArrayElement = Data; 243 244 static const MojomTypeCategory category = MojomTypeCategory::ENUM; 245}; 246 247template <typename T> 248struct MojomTypeTraits<ScopedHandleBase<T>, false> { 249 using Data = Handle_Data; 250 using DataAsArrayElement = Data; 251 252 static const MojomTypeCategory category = MojomTypeCategory::HANDLE; 253}; 254 255template <typename T> 256struct MojomTypeTraits<InterfacePtr<T>, false> { 257 using Data = Interface_Data; 258 using DataAsArrayElement = Data; 259 260 static const MojomTypeCategory category = MojomTypeCategory::INTERFACE; 261}; 262 263template <typename T> 264struct MojomTypeTraits<InterfaceRequest<T>, false> { 265 using Data = Handle_Data; 266 using DataAsArrayElement = Data; 267 268 static const MojomTypeCategory category = 269 MojomTypeCategory::INTERFACE_REQUEST; 270}; 271 272template <typename K, typename V> 273struct MojomTypeTraits<Map<K, V>, false> { 274 using Data = Map_Data<typename MojomTypeTraits<K>::DataAsArrayElement, 275 typename MojomTypeTraits<V>::DataAsArrayElement>; 276 using DataAsArrayElement = Pointer<Data>; 277 278 static const MojomTypeCategory category = MojomTypeCategory::MAP; 279}; 280 281template <> 282struct MojomTypeTraits<String, false> { 283 using Data = String_Data; 284 using DataAsArrayElement = Pointer<Data>; 285 286 static const MojomTypeCategory category = MojomTypeCategory::STRING; 287}; 288 289template <typename T> 290struct MojomTypeTraits<StructPtr<T>, false> { 291 using Data = typename T::Data_; 292 using DataAsArrayElement = 293 typename std::conditional<IsUnionDataType<Data>::value, 294 Data, 295 Pointer<Data>>::type; 296 297 static const MojomTypeCategory category = IsUnionDataType<Data>::value 298 ? MojomTypeCategory::UNION 299 : MojomTypeCategory::STRUCT; 300}; 301 302template <typename T> 303struct MojomTypeTraits<InlinedStructPtr<T>, false> { 304 using Data = typename T::Data_; 305 using DataAsArrayElement = 306 typename std::conditional<IsUnionDataType<Data>::value, 307 Data, 308 Pointer<Data>>::type; 309 310 static const MojomTypeCategory category = IsUnionDataType<Data>::value 311 ? MojomTypeCategory::UNION 312 : MojomTypeCategory::STRUCT; 313}; 314 315template <typename T, MojomTypeCategory categories> 316struct BelongsTo { 317 static const bool value = 318 static_cast<uint32_t>(MojomTypeTraits<T>::category & categories) != 0; 319}; 320 321template <typename T> 322struct EnumHashImpl { 323 static_assert(std::is_enum<T>::value, "Incorrect hash function."); 324 325 size_t operator()(T input) const { 326 using UnderlyingType = typename base::underlying_type<T>::type; 327 return std::hash<UnderlyingType>()(static_cast<UnderlyingType>(input)); 328 } 329}; 330 331} // namespace internal 332} // namespace mojo 333 334#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_ 335