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
Align(size_t size)58 inline size_t Align(size_t size) {
59 return (size + 7) & ~0x7;
60 }
61
IsAligned(const void * ptr)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 //
EncodePointer(const void * ptr,uint64_t * offset)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.
DecodePointer(const uint64_t * offset)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
SetPointer112 void Set(T* ptr) { EncodePointer(ptr, &offset); }
GetPointer113 const T* Get() const { return static_cast<const T*>(DecodePointer(&offset)); }
GetPointer114 T* Get() {
115 return static_cast<T*>(const_cast<void*>(DecodePointer(&offset)));
116 }
117
is_nullPointer118 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;
Handle_DataHandle_Data128 explicit Handle_Data(uint32_t value) : value(value) {}
129
is_validHandle_Data130 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;
AssociatedEndpointHandle_DataAssociatedEndpointHandle_Data144 explicit AssociatedEndpointHandle_Data(uint32_t value) : value(value) {}
145
is_validAssociatedEndpointHandle_Data146 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>
FetchAndReset(T * ptr)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