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.
DecodePointer(const uint64_t * offset)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
SetPointer102 void Set(T* ptr) { EncodePointer(ptr, &offset); }
GetPointer103 const T* Get() const { return static_cast<const T*>(DecodePointer(&offset)); }
GetPointer104 T* Get() {
105 return static_cast<T*>(const_cast<void*>(DecodePointer(&offset)));
106 }
107
is_nullPointer108 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;
Handle_DataHandle_Data116 explicit Handle_Data(uint32_t value) : value(value) {}
117
is_validHandle_Data118 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>
FetchAndReset(T * ptr)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