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