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