Home | History | Annotate | Download | only in lib
      1 // Copyright 2014 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_ARRAY_SERIALIZATION_H_
      6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_
      7 
      8 #include <stddef.h>
      9 #include <string.h>  // For |memcpy()|.
     10 
     11 #include <limits>
     12 #include <type_traits>
     13 #include <utility>
     14 #include <vector>
     15 
     16 #include "base/logging.h"
     17 #include "mojo/public/cpp/bindings/array_data_view.h"
     18 #include "mojo/public/cpp/bindings/lib/array_internal.h"
     19 #include "mojo/public/cpp/bindings/lib/serialization_forward.h"
     20 #include "mojo/public/cpp/bindings/lib/template_util.h"
     21 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
     22 
     23 namespace mojo {
     24 namespace internal {
     25 
     26 template <typename Traits,
     27           typename MaybeConstUserType,
     28           bool HasGetBegin =
     29               HasGetBeginMethod<Traits, MaybeConstUserType>::value>
     30 class ArrayIterator {};
     31 
     32 // Used as the UserTypeIterator template parameter of ArraySerializer.
     33 template <typename Traits, typename MaybeConstUserType>
     34 class ArrayIterator<Traits, MaybeConstUserType, true> {
     35  public:
     36   using IteratorType = decltype(
     37       CallGetBeginIfExists<Traits>(std::declval<MaybeConstUserType&>()));
     38 
     39   explicit ArrayIterator(MaybeConstUserType& input)
     40       : input_(input), iter_(CallGetBeginIfExists<Traits>(input)) {}
     41   ~ArrayIterator() {}
     42 
     43   size_t GetSize() const { return Traits::GetSize(input_); }
     44 
     45   using GetNextResult =
     46       decltype(Traits::GetValue(std::declval<IteratorType&>()));
     47   GetNextResult GetNext() {
     48     GetNextResult value = Traits::GetValue(iter_);
     49     Traits::AdvanceIterator(iter_);
     50     return value;
     51   }
     52 
     53   using GetDataIfExistsResult = decltype(
     54       CallGetDataIfExists<Traits>(std::declval<MaybeConstUserType&>()));
     55   GetDataIfExistsResult GetDataIfExists() {
     56     return CallGetDataIfExists<Traits>(input_);
     57   }
     58 
     59  private:
     60   MaybeConstUserType& input_;
     61   IteratorType iter_;
     62 };
     63 
     64 // Used as the UserTypeIterator template parameter of ArraySerializer.
     65 template <typename Traits, typename MaybeConstUserType>
     66 class ArrayIterator<Traits, MaybeConstUserType, false> {
     67  public:
     68   explicit ArrayIterator(MaybeConstUserType& input) : input_(input), iter_(0) {}
     69   ~ArrayIterator() {}
     70 
     71   size_t GetSize() const { return Traits::GetSize(input_); }
     72 
     73   using GetNextResult =
     74       decltype(Traits::GetAt(std::declval<MaybeConstUserType&>(), 0));
     75   GetNextResult GetNext() {
     76     DCHECK_LT(iter_, Traits::GetSize(input_));
     77     return Traits::GetAt(input_, iter_++);
     78   }
     79 
     80   using GetDataIfExistsResult = decltype(
     81       CallGetDataIfExists<Traits>(std::declval<MaybeConstUserType&>()));
     82   GetDataIfExistsResult GetDataIfExists() {
     83     return CallGetDataIfExists<Traits>(input_);
     84   }
     85 
     86  private:
     87   MaybeConstUserType& input_;
     88   size_t iter_;
     89 };
     90 
     91 // ArraySerializer is also used to serialize map keys and values. Therefore, it
     92 // has a UserTypeIterator parameter which is an adaptor for reading to hide the
     93 // difference between ArrayTraits and MapTraits.
     94 template <typename MojomType,
     95           typename MaybeConstUserType,
     96           typename UserTypeIterator,
     97           typename EnableType = void>
     98 struct ArraySerializer;
     99 
    100 // Handles serialization and deserialization of arrays of pod types.
    101 template <typename MojomType,
    102           typename MaybeConstUserType,
    103           typename UserTypeIterator>
    104 struct ArraySerializer<
    105     MojomType,
    106     MaybeConstUserType,
    107     UserTypeIterator,
    108     typename std::enable_if<BelongsTo<typename MojomType::Element,
    109                                       MojomTypeCategory::POD>::value>::type> {
    110   using UserType = typename std::remove_const<MaybeConstUserType>::type;
    111   using Data = typename MojomTypeTraits<MojomType>::Data;
    112   using DataElement = typename Data::Element;
    113   using Element = typename MojomType::Element;
    114   using Traits = ArrayTraits<UserType>;
    115   using BufferWriter = typename Data::BufferWriter;
    116 
    117   static_assert(std::is_same<Element, DataElement>::value,
    118                 "Incorrect array serializer");
    119   static_assert(
    120       std::is_same<
    121           Element,
    122           typename std::remove_const<typename Traits::Element>::type>::value,
    123       "Incorrect array serializer");
    124 
    125   static void SerializeElements(UserTypeIterator* input,
    126                                 Buffer* buf,
    127                                 BufferWriter* writer,
    128                                 const ContainerValidateParams* validate_params,
    129                                 SerializationContext* context) {
    130     DCHECK(!validate_params->element_is_nullable)
    131         << "Primitive type should be non-nullable";
    132     DCHECK(!validate_params->element_validate_params)
    133         << "Primitive type should not have array validate params";
    134 
    135     size_t size = input->GetSize();
    136     if (size == 0)
    137       return;
    138 
    139     auto data = input->GetDataIfExists();
    140     Data* output = writer->data();
    141     if (data) {
    142       memcpy(output->storage(), data, size * sizeof(DataElement));
    143     } else {
    144       for (size_t i = 0; i < size; ++i)
    145         output->at(i) = input->GetNext();
    146     }
    147   }
    148 
    149   static bool DeserializeElements(Data* input,
    150                                   UserType* output,
    151                                   SerializationContext* context) {
    152     if (!Traits::Resize(*output, input->size()))
    153       return false;
    154     ArrayIterator<Traits, UserType> iterator(*output);
    155     if (input->size()) {
    156       auto data = iterator.GetDataIfExists();
    157       if (data) {
    158         memcpy(data, input->storage(), input->size() * sizeof(DataElement));
    159       } else {
    160         for (size_t i = 0; i < input->size(); ++i)
    161           iterator.GetNext() = input->at(i);
    162       }
    163     }
    164     return true;
    165   }
    166 };
    167 
    168 // Handles serialization and deserialization of arrays of enum types.
    169 template <typename MojomType,
    170           typename MaybeConstUserType,
    171           typename UserTypeIterator>
    172 struct ArraySerializer<
    173     MojomType,
    174     MaybeConstUserType,
    175     UserTypeIterator,
    176     typename std::enable_if<BelongsTo<typename MojomType::Element,
    177                                       MojomTypeCategory::ENUM>::value>::type> {
    178   using UserType = typename std::remove_const<MaybeConstUserType>::type;
    179   using Data = typename MojomTypeTraits<MojomType>::Data;
    180   using DataElement = typename Data::Element;
    181   using Element = typename MojomType::Element;
    182   using Traits = ArrayTraits<UserType>;
    183   using BufferWriter = typename Data::BufferWriter;
    184 
    185   static_assert(sizeof(Element) == sizeof(DataElement),
    186                 "Incorrect array serializer");
    187 
    188   static void SerializeElements(UserTypeIterator* input,
    189                                 Buffer* buf,
    190                                 BufferWriter* writer,
    191                                 const ContainerValidateParams* validate_params,
    192                                 SerializationContext* context) {
    193     DCHECK(!validate_params->element_is_nullable)
    194         << "Primitive type should be non-nullable";
    195     DCHECK(!validate_params->element_validate_params)
    196         << "Primitive type should not have array validate params";
    197 
    198     Data* output = writer->data();
    199     size_t size = input->GetSize();
    200     for (size_t i = 0; i < size; ++i)
    201       Serialize<Element>(input->GetNext(), output->storage() + i);
    202   }
    203 
    204   static bool DeserializeElements(Data* input,
    205                                   UserType* output,
    206                                   SerializationContext* context) {
    207     if (!Traits::Resize(*output, input->size()))
    208       return false;
    209     ArrayIterator<Traits, UserType> iterator(*output);
    210     for (size_t i = 0; i < input->size(); ++i) {
    211       if (!Deserialize<Element>(input->at(i), &iterator.GetNext()))
    212         return false;
    213     }
    214     return true;
    215   }
    216 };
    217 
    218 // Serializes and deserializes arrays of bools.
    219 template <typename MojomType,
    220           typename MaybeConstUserType,
    221           typename UserTypeIterator>
    222 struct ArraySerializer<MojomType,
    223                        MaybeConstUserType,
    224                        UserTypeIterator,
    225                        typename std::enable_if<BelongsTo<
    226                            typename MojomType::Element,
    227                            MojomTypeCategory::BOOLEAN>::value>::type> {
    228   using UserType = typename std::remove_const<MaybeConstUserType>::type;
    229   using Traits = ArrayTraits<UserType>;
    230   using Data = typename MojomTypeTraits<MojomType>::Data;
    231   using BufferWriter = typename Data::BufferWriter;
    232 
    233   static_assert(std::is_same<bool, typename Traits::Element>::value,
    234                 "Incorrect array serializer");
    235 
    236   static void SerializeElements(UserTypeIterator* input,
    237                                 Buffer* buf,
    238                                 BufferWriter* writer,
    239                                 const ContainerValidateParams* validate_params,
    240                                 SerializationContext* context) {
    241     DCHECK(!validate_params->element_is_nullable)
    242         << "Primitive type should be non-nullable";
    243     DCHECK(!validate_params->element_validate_params)
    244         << "Primitive type should not have array validate params";
    245 
    246     Data* output = writer->data();
    247     size_t size = input->GetSize();
    248     for (size_t i = 0; i < size; ++i)
    249       output->at(i) = input->GetNext();
    250   }
    251   static bool DeserializeElements(Data* input,
    252                                   UserType* output,
    253                                   SerializationContext* context) {
    254     if (!Traits::Resize(*output, input->size()))
    255       return false;
    256     ArrayIterator<Traits, UserType> iterator(*output);
    257     for (size_t i = 0; i < input->size(); ++i)
    258       iterator.GetNext() = input->at(i);
    259     return true;
    260   }
    261 };
    262 
    263 // Serializes and deserializes arrays of handles or interfaces.
    264 template <typename MojomType,
    265           typename MaybeConstUserType,
    266           typename UserTypeIterator>
    267 struct ArraySerializer<
    268     MojomType,
    269     MaybeConstUserType,
    270     UserTypeIterator,
    271     typename std::enable_if<
    272         BelongsTo<typename MojomType::Element,
    273                   MojomTypeCategory::ASSOCIATED_INTERFACE |
    274                       MojomTypeCategory::ASSOCIATED_INTERFACE_REQUEST |
    275                       MojomTypeCategory::HANDLE | MojomTypeCategory::INTERFACE |
    276                       MojomTypeCategory::INTERFACE_REQUEST>::value>::type> {
    277   using UserType = typename std::remove_const<MaybeConstUserType>::type;
    278   using Data = typename MojomTypeTraits<MojomType>::Data;
    279   using Element = typename MojomType::Element;
    280   using Traits = ArrayTraits<UserType>;
    281   using BufferWriter = typename Data::BufferWriter;
    282 
    283   static void SerializeElements(UserTypeIterator* input,
    284                                 Buffer* buf,
    285                                 BufferWriter* writer,
    286                                 const ContainerValidateParams* validate_params,
    287                                 SerializationContext* context) {
    288     DCHECK(!validate_params->element_validate_params)
    289         << "Handle or interface type should not have array validate params";
    290 
    291     Data* output = writer->data();
    292     size_t size = input->GetSize();
    293     for (size_t i = 0; i < size; ++i) {
    294       typename UserTypeIterator::GetNextResult next = input->GetNext();
    295       Serialize<Element>(next, &output->at(i), context);
    296 
    297       static const ValidationError kError =
    298           BelongsTo<Element,
    299                     MojomTypeCategory::ASSOCIATED_INTERFACE |
    300                         MojomTypeCategory::ASSOCIATED_INTERFACE_REQUEST>::value
    301               ? VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID
    302               : VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE;
    303       MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
    304           !validate_params->element_is_nullable &&
    305               !IsHandleOrInterfaceValid(output->at(i)),
    306           kError,
    307           MakeMessageWithArrayIndex("invalid handle or interface ID in array "
    308                                     "expecting valid handles or interface IDs",
    309                                     size, i));
    310     }
    311   }
    312   static bool DeserializeElements(Data* input,
    313                                   UserType* output,
    314                                   SerializationContext* context) {
    315     if (!Traits::Resize(*output, input->size()))
    316       return false;
    317     ArrayIterator<Traits, UserType> iterator(*output);
    318     for (size_t i = 0; i < input->size(); ++i) {
    319       bool result =
    320           Deserialize<Element>(&input->at(i), &iterator.GetNext(), context);
    321       DCHECK(result);
    322     }
    323     return true;
    324   }
    325 };
    326 
    327 // This template must only apply to pointer mojo entity (strings, structs,
    328 // arrays and maps).
    329 template <typename MojomType,
    330           typename MaybeConstUserType,
    331           typename UserTypeIterator>
    332 struct ArraySerializer<MojomType,
    333                        MaybeConstUserType,
    334                        UserTypeIterator,
    335                        typename std::enable_if<BelongsTo<
    336                            typename MojomType::Element,
    337                            MojomTypeCategory::ARRAY | MojomTypeCategory::MAP |
    338                                MojomTypeCategory::STRING |
    339                                MojomTypeCategory::STRUCT>::value>::type> {
    340   using UserType = typename std::remove_const<MaybeConstUserType>::type;
    341   using Data = typename MojomTypeTraits<MojomType>::Data;
    342   using Element = typename MojomType::Element;
    343   using DataElementWriter =
    344       typename MojomTypeTraits<Element>::Data::BufferWriter;
    345   using Traits = ArrayTraits<UserType>;
    346   using BufferWriter = typename Data::BufferWriter;
    347 
    348   static void SerializeElements(UserTypeIterator* input,
    349                                 Buffer* buf,
    350                                 BufferWriter* writer,
    351                                 const ContainerValidateParams* validate_params,
    352                                 SerializationContext* context) {
    353     size_t size = input->GetSize();
    354     for (size_t i = 0; i < size; ++i) {
    355       DataElementWriter data_writer;
    356       typename UserTypeIterator::GetNextResult next = input->GetNext();
    357       SerializeCaller<Element>::Run(next, buf, &data_writer,
    358                                     validate_params->element_validate_params,
    359                                     context);
    360       writer->data()->at(i).Set(data_writer.is_null() ? nullptr
    361                                                       : data_writer.data());
    362       MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
    363           !validate_params->element_is_nullable && data_writer.is_null(),
    364           VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
    365           MakeMessageWithArrayIndex("null in array expecting valid pointers",
    366                                     size, i));
    367     }
    368   }
    369   static bool DeserializeElements(Data* input,
    370                                   UserType* output,
    371                                   SerializationContext* context) {
    372     if (!Traits::Resize(*output, input->size()))
    373       return false;
    374     ArrayIterator<Traits, UserType> iterator(*output);
    375     for (size_t i = 0; i < input->size(); ++i) {
    376       if (!Deserialize<Element>(input->at(i).Get(), &iterator.GetNext(),
    377                                 context))
    378         return false;
    379     }
    380     return true;
    381   }
    382 
    383  private:
    384   template <typename T,
    385             bool is_array_or_map = BelongsTo<T,
    386                                              MojomTypeCategory::ARRAY |
    387                                                  MojomTypeCategory::MAP>::value>
    388   struct SerializeCaller {
    389     template <typename InputElementType>
    390     static void Run(InputElementType&& input,
    391                     Buffer* buf,
    392                     DataElementWriter* writer,
    393                     const ContainerValidateParams* validate_params,
    394                     SerializationContext* context) {
    395       Serialize<T>(std::forward<InputElementType>(input), buf, writer, context);
    396     }
    397   };
    398 
    399   template <typename T>
    400   struct SerializeCaller<T, true> {
    401     template <typename InputElementType>
    402     static void Run(InputElementType&& input,
    403                     Buffer* buf,
    404                     DataElementWriter* writer,
    405                     const ContainerValidateParams* validate_params,
    406                     SerializationContext* context) {
    407       Serialize<T>(std::forward<InputElementType>(input), buf, writer,
    408                    validate_params, context);
    409     }
    410   };
    411 };
    412 
    413 // Handles serialization and deserialization of arrays of unions.
    414 template <typename MojomType,
    415           typename MaybeConstUserType,
    416           typename UserTypeIterator>
    417 struct ArraySerializer<
    418     MojomType,
    419     MaybeConstUserType,
    420     UserTypeIterator,
    421     typename std::enable_if<BelongsTo<typename MojomType::Element,
    422                                       MojomTypeCategory::UNION>::value>::type> {
    423   using UserType = typename std::remove_const<MaybeConstUserType>::type;
    424   using Data = typename MojomTypeTraits<MojomType>::Data;
    425   using Element = typename MojomType::Element;
    426   using ElementWriter = typename Data::Element::BufferWriter;
    427   using Traits = ArrayTraits<UserType>;
    428   using BufferWriter = typename Data::BufferWriter;
    429 
    430   static void SerializeElements(UserTypeIterator* input,
    431                                 Buffer* buf,
    432                                 BufferWriter* writer,
    433                                 const ContainerValidateParams* validate_params,
    434                                 SerializationContext* context) {
    435     size_t size = input->GetSize();
    436     for (size_t i = 0; i < size; ++i) {
    437       ElementWriter result;
    438       result.AllocateInline(buf, writer->data()->storage() + i);
    439       typename UserTypeIterator::GetNextResult next = input->GetNext();
    440       Serialize<Element>(next, buf, &result, true, context);
    441       MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
    442           !validate_params->element_is_nullable &&
    443               writer->data()->at(i).is_null(),
    444           VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
    445           MakeMessageWithArrayIndex("null in array expecting valid unions",
    446                                     size, i));
    447     }
    448   }
    449 
    450   static bool DeserializeElements(Data* input,
    451                                   UserType* output,
    452                                   SerializationContext* context) {
    453     if (!Traits::Resize(*output, input->size()))
    454       return false;
    455     ArrayIterator<Traits, UserType> iterator(*output);
    456     for (size_t i = 0; i < input->size(); ++i) {
    457       if (!Deserialize<Element>(&input->at(i), &iterator.GetNext(), context))
    458         return false;
    459     }
    460     return true;
    461   }
    462 };
    463 
    464 template <typename Element, typename MaybeConstUserType>
    465 struct Serializer<ArrayDataView<Element>, MaybeConstUserType> {
    466   using UserType = typename std::remove_const<MaybeConstUserType>::type;
    467   using Traits = ArrayTraits<UserType>;
    468   using Impl = ArraySerializer<ArrayDataView<Element>,
    469                                MaybeConstUserType,
    470                                ArrayIterator<Traits, MaybeConstUserType>>;
    471   using Data = typename MojomTypeTraits<ArrayDataView<Element>>::Data;
    472   using BufferWriter = typename Data::BufferWriter;
    473 
    474   static void Serialize(MaybeConstUserType& input,
    475                         Buffer* buf,
    476                         BufferWriter* writer,
    477                         const ContainerValidateParams* validate_params,
    478                         SerializationContext* context) {
    479     if (CallIsNullIfExists<Traits>(input))
    480       return;
    481 
    482     const size_t size = Traits::GetSize(input);
    483     MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
    484         validate_params->expected_num_elements != 0 &&
    485             size != validate_params->expected_num_elements,
    486         internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER,
    487         internal::MakeMessageWithExpectedArraySize(
    488             "fixed-size array has wrong number of elements", size,
    489             validate_params->expected_num_elements));
    490     writer->Allocate(size, buf);
    491     ArrayIterator<Traits, MaybeConstUserType> iterator(input);
    492     Impl::SerializeElements(&iterator, buf, writer, validate_params, context);
    493   }
    494 
    495   static bool Deserialize(Data* input,
    496                           UserType* output,
    497                           SerializationContext* context) {
    498     if (!input)
    499       return CallSetToNullIfExists<Traits>(output);
    500     return Impl::DeserializeElements(input, output, context);
    501   }
    502 };
    503 
    504 }  // namespace internal
    505 }  // namespace mojo
    506 
    507 #endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_
    508