• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ArrayIterator(MaybeConstUserType & input)39   explicit ArrayIterator(MaybeConstUserType& input)
40       : input_(input), iter_(CallGetBeginIfExists<Traits>(input)) {}
~ArrayIterator()41   ~ArrayIterator() {}
42 
GetSize()43   size_t GetSize() const { return Traits::GetSize(input_); }
44 
45   using GetNextResult =
46       decltype(Traits::GetValue(std::declval<IteratorType&>()));
GetNext()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&>()));
GetDataIfExists()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:
ArrayIterator(MaybeConstUserType & input)68   explicit ArrayIterator(MaybeConstUserType& input) : input_(input), iter_(0) {}
~ArrayIterator()69   ~ArrayIterator() {}
70 
GetSize()71   size_t GetSize() const { return Traits::GetSize(input_); }
72 
73   using GetNextResult =
74       decltype(Traits::GetAt(std::declval<MaybeConstUserType&>(), 0));
GetNext()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&>()));
GetDataIfExists()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