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 17 namespace mojo { 18 19 template <typename T> 20 class Array; 21 22 template <typename T> 23 class AssociatedInterfacePtrInfo; 24 25 template <typename T> 26 class AssociatedInterfaceRequest; 27 28 template <typename T> 29 class InterfacePtr; 30 31 template <typename T> 32 class InterfaceRequest; 33 34 template <typename K, typename V> 35 class Map; 36 37 class String; 38 39 template <typename T> 40 class StructPtr; 41 42 template <typename T> 43 class InlinedStructPtr; 44 45 namespace internal { 46 47 // Please note that this is a different value than |mojo::kInvalidHandleValue|, 48 // which is the "decoded" invalid handle. 49 const 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. 53 const uint32_t kUnionDataSize = 16; 54 55 template <typename T> 56 class Array_Data; 57 58 template <typename K, typename V> 59 class Map_Data; 60 61 using String_Data = Array_Data<char>; 62 63 size_t Align(size_t size); 64 char* AlignPointer(char* ptr); 65 66 bool 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 // 76 void EncodePointer(const void* ptr, uint64_t* offset); 77 // Note: This function doesn't validate the encoded pointer value. 78 inline 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 86 struct StructHeader { 87 uint32_t num_bytes; 88 uint32_t version; 89 }; 90 static_assert(sizeof(StructHeader) == 8, "Bad sizeof(StructHeader)"); 91 92 struct ArrayHeader { 93 uint32_t num_bytes; 94 uint32_t num_elements; 95 }; 96 static_assert(sizeof(ArrayHeader) == 8, "Bad_sizeof(ArrayHeader)"); 97 98 template <typename T> 99 struct 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 }; 112 static_assert(sizeof(Pointer<char>) == 8, "Bad_sizeof(Pointer)"); 113 114 struct 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 }; 122 static_assert(sizeof(Handle_Data) == 4, "Bad_sizeof(Handle_Data)"); 123 124 struct Interface_Data { 125 Handle_Data handle; 126 uint32_t version; 127 }; 128 static_assert(sizeof(Interface_Data) == 8, "Bad_sizeof(Interface_Data)"); 129 130 struct AssociatedInterface_Data { 131 InterfaceId interface_id; 132 uint32_t version; 133 }; 134 static_assert(sizeof(AssociatedInterface_Data) == 8, 135 "Bad_sizeof(AssociatedInterface_Data)"); 136 137 struct AssociatedInterfaceRequest_Data { 138 InterfaceId interface_id; 139 }; 140 static_assert(sizeof(AssociatedInterfaceRequest_Data) == 4, 141 "Bad_sizeof(AssociatedInterfaceRequest_Data)"); 142 143 #pragma pack(pop) 144 145 template <typename T> 146 T FetchAndReset(T* ptr) { 147 T temp = *ptr; 148 *ptr = T(); 149 return temp; 150 } 151 152 template <typename T> 153 struct 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 168 enum 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 185 inline 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 191 inline 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 197 template <typename T, bool is_enum = std::is_enum<T>::value> 198 struct MojomTypeTraits { 199 using Data = T; 200 using DataAsArrayElement = Data; 201 202 static const MojomTypeCategory category = MojomTypeCategory::POD; 203 }; 204 205 template <typename T> 206 struct 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 213 template <typename T> 214 struct 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 222 template <typename T> 223 struct 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 231 template <> 232 struct MojomTypeTraits<bool, false> { 233 using Data = bool; 234 using DataAsArrayElement = Data; 235 236 static const MojomTypeCategory category = MojomTypeCategory::BOOLEAN; 237 }; 238 239 template <typename T> 240 struct MojomTypeTraits<T, true> { 241 using Data = int32_t; 242 using DataAsArrayElement = Data; 243 244 static const MojomTypeCategory category = MojomTypeCategory::ENUM; 245 }; 246 247 template <typename T> 248 struct MojomTypeTraits<ScopedHandleBase<T>, false> { 249 using Data = Handle_Data; 250 using DataAsArrayElement = Data; 251 252 static const MojomTypeCategory category = MojomTypeCategory::HANDLE; 253 }; 254 255 template <typename T> 256 struct MojomTypeTraits<InterfacePtr<T>, false> { 257 using Data = Interface_Data; 258 using DataAsArrayElement = Data; 259 260 static const MojomTypeCategory category = MojomTypeCategory::INTERFACE; 261 }; 262 263 template <typename T> 264 struct 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 272 template <typename K, typename V> 273 struct 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 281 template <> 282 struct MojomTypeTraits<String, false> { 283 using Data = String_Data; 284 using DataAsArrayElement = Pointer<Data>; 285 286 static const MojomTypeCategory category = MojomTypeCategory::STRING; 287 }; 288 289 template <typename T> 290 struct 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 302 template <typename T> 303 struct 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 315 template <typename T, MojomTypeCategory categories> 316 struct BelongsTo { 317 static const bool value = 318 static_cast<uint32_t>(MojomTypeTraits<T>::category & categories) != 0; 319 }; 320 321 template <typename T> 322 struct 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