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