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