Home | History | Annotate | Download | only in lib
      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 
     58 inline size_t Align(size_t size) {
     59   return (size + 7) & ~0x7;
     60 }
     61 
     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 //
     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.
     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 
    112   void Set(T* ptr) { EncodePointer(ptr, &offset); }
    113   const T* Get() const { return static_cast<const T*>(DecodePointer(&offset)); }
    114   T* Get() {
    115     return static_cast<T*>(const_cast<void*>(DecodePointer(&offset)));
    116   }
    117 
    118   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;
    128   explicit Handle_Data(uint32_t value) : value(value) {}
    129 
    130   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;
    144   explicit AssociatedEndpointHandle_Data(uint32_t value) : value(value) {}
    145 
    146   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>
    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