OLD | NEW |
| (Empty) |
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 // TODO(vardhan): Currently, the logic for serializing a mojom type exists in | |
6 // two places: the C++ code generator template, and here. However, most types | |
7 // are serialized the same way within Arrays or outside, with the exception of | |
8 // |bool|. Consider defining serialization/deserialization traits for each | |
9 // serializable type and call those traits from here. This should help us | |
10 // remove most of the ArraySerializer<> specializations here. | |
11 | |
12 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ | |
13 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ | |
14 | |
15 #include <string.h> // For |memcpy()|. | |
16 #include <type_traits> | |
17 #include <vector> | |
18 | |
19 #include "mojo/public/cpp/bindings/lib/array_internal.h" | |
20 #include "mojo/public/cpp/bindings/lib/bindings_internal.h" | |
21 #include "mojo/public/cpp/bindings/lib/iterator_util.h" | |
22 #include "mojo/public/cpp/bindings/lib/map_data_internal.h" | |
23 #include "mojo/public/cpp/bindings/lib/map_serialization_forward.h" | |
24 #include "mojo/public/cpp/bindings/lib/string_serialization.h" | |
25 #include "mojo/public/cpp/bindings/lib/validation_errors.h" | |
26 | |
27 namespace mojo { | |
28 | |
29 namespace internal { | |
30 | |
31 // The ArraySerializer template contains static methods for serializing |Array|s | |
32 // of various types. These methods include: | |
33 // * size_t GetSerializedSize(..) | |
34 // Computes the size of the serialized version of the |Array|. | |
35 // * void SerializeElements(..) | |
36 // Takes an |Iterator| and a size and serializes it. | |
37 // * void DeserializeElements(..) | |
38 // Takes a pointer to an |Array_Data| and deserializes it into a given | |
39 // |Array|. | |
40 // | |
41 // Note: The enable template parameter exists only to allow partial | |
42 // specializations to disable instantiation using logic based on E and F. | |
43 // By default, assuming that there are no other substitution failures, the | |
44 // specialization will instantiate and needs to take no action. A partial | |
45 // specialization of the form | |
46 // | |
47 // template<E, F> struct ArraySerialzer<E, F> | |
48 // | |
49 // may be limited to values of E and F with particular properties by supplying | |
50 // an expression for enable which will cause substitution failure if the | |
51 // properties of E and F do not satisfy the expression. | |
52 template <typename E, | |
53 typename F, | |
54 bool is_union = | |
55 IsUnionDataType<typename std::remove_pointer<F>::type>::value, | |
56 typename enable = void> | |
57 struct ArraySerializer; | |
58 | |
59 // Handles serialization and deserialization of arrays of pod types. | |
60 template <typename E, typename F> | |
61 struct ArraySerializer< | |
62 E, | |
63 F, | |
64 false, | |
65 typename std::enable_if<std::is_convertible<E, F>::value || | |
66 (std::is_enum<E>::value && | |
67 std::is_same<F, int32_t>::value), | |
68 void>::type> { | |
69 static_assert(sizeof(E) == sizeof(F), "Incorrect array serializer"); | |
70 static size_t GetSerializedSize(const Array<E>& input) { | |
71 return sizeof(Array_Data<F>) + Align(input.size() * sizeof(E)); | |
72 } | |
73 | |
74 template <typename Iterator> | |
75 static ValidationError SerializeElements( | |
76 Iterator it, | |
77 size_t num_elements, | |
78 Buffer* buf, | |
79 Array_Data<F>* output, | |
80 const ArrayValidateParams* validate_params) { | |
81 MOJO_DCHECK(!validate_params->element_is_nullable) | |
82 << "Primitive type should be non-nullable"; | |
83 MOJO_DCHECK(!validate_params->element_validate_params) | |
84 << "Primitive type should not have array validate params"; | |
85 for (size_t i = 0; i < num_elements; ++i, ++it) | |
86 output->at(i) = static_cast<F>(*it); | |
87 | |
88 return ValidationError::NONE; | |
89 } | |
90 | |
91 // We can optimize serializing PODs by |memcpy|ing directly. | |
92 // Note that this has precedence over its templated sibling defined above. | |
93 static ValidationError SerializeElements( | |
94 typename Array<E>::Iterator it, | |
95 size_t num_elements, | |
96 Buffer* buf, | |
97 Array_Data<F>* output, | |
98 const ArrayValidateParams* validate_params) { | |
99 MOJO_DCHECK(!validate_params->element_is_nullable) | |
100 << "Primitive type should be non-nullable"; | |
101 MOJO_DCHECK(!validate_params->element_validate_params) | |
102 << "Primitive type should not have array validate params"; | |
103 if (num_elements) | |
104 memcpy(output->storage(), &(*it), num_elements * sizeof(E)); | |
105 | |
106 return ValidationError::NONE; | |
107 } | |
108 | |
109 static void DeserializeElements(Array_Data<F>* input, Array<E>* output) { | |
110 std::vector<E> result(input->size()); | |
111 if (input->size()) | |
112 memcpy(&result[0], input->storage(), input->size() * sizeof(E)); | |
113 output->Swap(&result); | |
114 } | |
115 }; | |
116 | |
117 // Serializes and deserializes arrays of bools. | |
118 template <> | |
119 struct ArraySerializer<bool, bool, false> { | |
120 static size_t GetSerializedSize(const Array<bool>& input) { | |
121 return sizeof(Array_Data<bool>) + Align((input.size() + 7) / 8); | |
122 } | |
123 | |
124 template <typename Iterator> | |
125 static ValidationError SerializeElements( | |
126 Iterator it, | |
127 size_t num_elements, | |
128 Buffer* buf, | |
129 Array_Data<bool>* output, | |
130 const ArrayValidateParams* validate_params) { | |
131 MOJO_DCHECK(!validate_params->element_is_nullable) | |
132 << "Primitive type should be non-nullable"; | |
133 MOJO_DCHECK(!validate_params->element_validate_params) | |
134 << "Primitive type should not have array validate params"; | |
135 | |
136 // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? | |
137 for (size_t i = 0; i < num_elements; ++i, ++it) | |
138 output->at(i) = *it; | |
139 | |
140 return ValidationError::NONE; | |
141 } | |
142 | |
143 static void DeserializeElements(Array_Data<bool>* input, | |
144 Array<bool>* output) { | |
145 auto result = Array<bool>::New(input->size()); | |
146 // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? | |
147 for (size_t i = 0; i < input->size(); ++i) | |
148 result.at(i) = input->at(i); | |
149 output->Swap(&result); | |
150 } | |
151 }; | |
152 | |
153 // Serializes and deserializes arrays of handles. | |
154 template <typename H> | |
155 struct ArraySerializer<ScopedHandleBase<H>, H, false> { | |
156 static size_t GetSerializedSize(const Array<ScopedHandleBase<H>>& input) { | |
157 return sizeof(Array_Data<H>) + Align(input.size() * sizeof(H)); | |
158 } | |
159 | |
160 template <typename Iterator> | |
161 static ValidationError SerializeElements( | |
162 Iterator it, | |
163 size_t num_elements, | |
164 Buffer* buf, | |
165 Array_Data<H>* output, | |
166 const ArrayValidateParams* validate_params) { | |
167 MOJO_DCHECK(!validate_params->element_validate_params) | |
168 << "Handle type should not have array validate params"; | |
169 | |
170 for (size_t i = 0; i < num_elements; ++i, ++it) { | |
171 // Transfer ownership of the handle. | |
172 output->at(i) = it->release(); | |
173 if (!validate_params->element_is_nullable && !output->at(i).is_valid()) { | |
174 MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( | |
175 ValidationError::UNEXPECTED_INVALID_HANDLE, | |
176 MakeMessageWithArrayIndex( | |
177 "invalid handle in array expecting valid handles", num_elements, | |
178 i)); | |
179 return ValidationError::UNEXPECTED_INVALID_HANDLE; | |
180 } | |
181 } | |
182 | |
183 return ValidationError::NONE; | |
184 } | |
185 | |
186 static void DeserializeElements(Array_Data<H>* input, | |
187 Array<ScopedHandleBase<H>>* output) { | |
188 auto result = Array<ScopedHandleBase<H>>::New(input->size()); | |
189 for (size_t i = 0; i < input->size(); ++i) | |
190 result.at(i) = MakeScopedHandle(FetchAndReset(&input->at(i))); | |
191 output->Swap(&result); | |
192 } | |
193 }; | |
194 | |
195 // Serializes and deserializes arrays of interface requests. | |
196 template <typename I> | |
197 struct ArraySerializer<InterfaceRequest<I>, MessagePipeHandle, false> { | |
198 static size_t GetSerializedSize(const Array<InterfaceRequest<I>>& input) { | |
199 return sizeof(Array_Data<MessagePipeHandle>) + | |
200 Align(input.size() * sizeof(MessagePipeHandle)); | |
201 } | |
202 | |
203 template <typename Iterator> | |
204 static ValidationError SerializeElements( | |
205 Iterator it, | |
206 size_t num_elements, | |
207 Buffer* buf, | |
208 Array_Data<MessagePipeHandle>* output, | |
209 const ArrayValidateParams* validate_params) { | |
210 MOJO_DCHECK(!validate_params->element_validate_params) | |
211 << "Handle type should not have array validate params"; | |
212 | |
213 for (size_t i = 0; i < num_elements; ++i, ++it) { | |
214 // Transfer ownership of the MessagePipeHandle. | |
215 output->at(i) = it->PassMessagePipe().release(); | |
216 if (!validate_params->element_is_nullable && !output->at(i).is_valid()) { | |
217 MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( | |
218 ValidationError::UNEXPECTED_INVALID_HANDLE, | |
219 MakeMessageWithArrayIndex( | |
220 "invalid message pipe handle in array expecting valid handles", | |
221 num_elements, i)); | |
222 return ValidationError::UNEXPECTED_INVALID_HANDLE; | |
223 } | |
224 } | |
225 | |
226 return ValidationError::NONE; | |
227 } | |
228 | |
229 static void DeserializeElements(Array_Data<MessagePipeHandle>* input, | |
230 Array<InterfaceRequest<I>>* output) { | |
231 auto result = Array<InterfaceRequest<I>>::New(input->size()); | |
232 for (size_t i = 0; i < input->size(); ++i) | |
233 result.at(i) = | |
234 InterfaceRequest<I>(MakeScopedHandle(FetchAndReset(&input->at(i)))) | |
235 .Pass(); | |
236 output->Swap(&result); | |
237 } | |
238 }; | |
239 | |
240 // Serializes and deserializes arrays of interfaces (interface handles). | |
241 template <typename Interface> | |
242 struct ArraySerializer<InterfaceHandle<Interface>, Interface_Data, false> { | |
243 static size_t GetSerializedSize( | |
244 const Array<InterfaceHandle<Interface>>& input) { | |
245 return sizeof(Array_Data<Interface_Data>) + | |
246 Align(input.size() * sizeof(Interface_Data)); | |
247 } | |
248 | |
249 template <typename Iterator> | |
250 static ValidationError SerializeElements( | |
251 Iterator it, | |
252 size_t num_elements, | |
253 Buffer* buf, | |
254 Array_Data<Interface_Data>* output, | |
255 const ArrayValidateParams* validate_params) { | |
256 MOJO_DCHECK(!validate_params->element_validate_params) | |
257 << "Interface type should not have array validate params"; | |
258 | |
259 for (size_t i = 0; i < num_elements; ++i, ++it) { | |
260 // Transfer ownership of the handle. | |
261 internal::InterfaceHandleToData(it->Pass(), &output->at(i)); | |
262 if (!validate_params->element_is_nullable && | |
263 !output->at(i).handle.is_valid()) { | |
264 MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( | |
265 ValidationError::UNEXPECTED_INVALID_HANDLE, | |
266 MakeMessageWithArrayIndex( | |
267 "invalid handle in array expecting valid handles", num_elements, | |
268 i)); | |
269 return ValidationError::UNEXPECTED_INVALID_HANDLE; | |
270 } | |
271 } | |
272 | |
273 return ValidationError::NONE; | |
274 } | |
275 | |
276 static void DeserializeElements(Array_Data<Interface_Data>* input, | |
277 Array<InterfaceHandle<Interface>>* output) { | |
278 auto result = Array<InterfaceHandle<Interface>>::New(input->size()); | |
279 for (size_t i = 0; i < input->size(); ++i) | |
280 internal::InterfaceDataToHandle(&input->at(i), &result.at(i)); | |
281 output->Swap(&result); | |
282 } | |
283 }; | |
284 | |
285 // This template must only apply to pointer mojo entity (structs, arrays, | |
286 // strings). This is done by ensuring that WrapperTraits<S>::DataType is a | |
287 // pointer. | |
288 template <typename S> | |
289 struct ArraySerializer< | |
290 S, | |
291 typename std::enable_if< | |
292 std::is_pointer<typename WrapperTraits<S>::DataType>::value, | |
293 typename WrapperTraits<S>::DataType>::type, | |
294 false> { | |
295 typedef | |
296 typename std::remove_pointer<typename WrapperTraits<S>::DataType>::type | |
297 S_Data; | |
298 static size_t GetSerializedSize(const Array<S>& input) { | |
299 size_t size = sizeof(Array_Data<S_Data*>) + | |
300 input.size() * sizeof(StructPointer<S_Data>); | |
301 for (size_t i = 0; i < input.size(); ++i) { | |
302 if (!input[i].is_null()) | |
303 size += GetSerializedSize_(*(UnwrapConstStructPtr<S>::value(input[i]))); | |
304 } | |
305 return size; | |
306 } | |
307 | |
308 template <typename Iterator> | |
309 static ValidationError SerializeElements( | |
310 Iterator it, | |
311 size_t num_elements, | |
312 Buffer* buf, | |
313 Array_Data<S_Data*>* output, | |
314 const ArrayValidateParams* validate_params) { | |
315 for (size_t i = 0; i < num_elements; ++i, ++it) { | |
316 S_Data* element; | |
317 auto retval = SerializeCaller::Run( | |
318 &(*it), buf, &element, validate_params->element_validate_params); | |
319 if (retval != ValidationError::NONE) | |
320 return retval; | |
321 | |
322 output->at(i) = element; | |
323 if (!validate_params->element_is_nullable && !element) { | |
324 MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( | |
325 ValidationError::UNEXPECTED_NULL_POINTER, | |
326 MakeMessageWithArrayIndex("null in array expecting valid pointers", | |
327 num_elements, i)); | |
328 return ValidationError::UNEXPECTED_NULL_POINTER; | |
329 } | |
330 } | |
331 | |
332 return ValidationError::NONE; | |
333 } | |
334 | |
335 static void DeserializeElements(Array_Data<S_Data*>* input, | |
336 Array<S>* output) { | |
337 auto result = Array<S>::New(input->size()); | |
338 for (size_t i = 0; i < input->size(); ++i) { | |
339 DeserializeCaller::Run(input->at(i), &result[i]); | |
340 } | |
341 output->Swap(&result); | |
342 } | |
343 | |
344 private: | |
345 // SerializeCaller template is used by |ArraySerializer| to dispatch a | |
346 // serialize call on a non-POD type. This template is defined outside | |
347 // |ArraySerializer| since you cannot specialize a struct within a class | |
348 // definition. | |
349 struct SerializeCaller { | |
350 // This template needs to be suppressed if |T| is |String|, otherwise it | |
351 // takes precedence over the |String|-overloaded Run() below. | |
352 template < | |
353 typename T, | |
354 typename = | |
355 typename std::enable_if<!std::is_same<T, String>::value, T>::type> | |
356 static ValidationError Run(T* input, | |
357 Buffer* buf, | |
358 typename WrapperTraits<T>::DataType* output, | |
359 const ArrayValidateParams* validate_params) { | |
360 MOJO_DCHECK(!validate_params) | |
361 << "Struct type should not have array validate params"; | |
362 return Serialize_(UnwrapStructPtr<T>::value(*input), buf, output); | |
363 } | |
364 | |
365 static ValidationError Run(const String* input, | |
366 Buffer* buf, | |
367 String_Data** output, | |
368 const ArrayValidateParams* validate_params) { | |
369 MOJO_DCHECK(validate_params && | |
370 !validate_params->element_validate_params && | |
371 !validate_params->element_is_nullable && | |
372 validate_params->expected_num_elements == 0) | |
373 << "String type has unexpected array validate params"; | |
374 SerializeString_(*input, buf, output); | |
375 return ValidationError::NONE; | |
376 } | |
377 | |
378 template <typename T> | |
379 static ValidationError Run(Array<T>* input, | |
380 Buffer* buf, | |
381 typename Array<T>::Data_** output, | |
382 const ArrayValidateParams* validate_params) { | |
383 return SerializeArray_(input, buf, output, validate_params); | |
384 } | |
385 | |
386 template <typename Key, typename Value> | |
387 static ValidationError Run(Map<Key, Value>* input, | |
388 Buffer* buf, | |
389 typename Map<Key, Value>::Data_** output, | |
390 const ArrayValidateParams* validate_params) { | |
391 return SerializeMap_(input, buf, output, validate_params); | |
392 } | |
393 }; | |
394 | |
395 struct DeserializeCaller { | |
396 template <typename T> | |
397 static void Run(typename WrapperTraits<T>::DataType input, T* output) { | |
398 Deserialize_(input, output); | |
399 } | |
400 | |
401 // Since Deserialize_ takes in a |Struct*| (not |StructPtr|), we need to | |
402 // initialize the |StructPtr| here before deserializing into its underlying | |
403 // data. | |
404 // TODO(vardhan): Either all containers, or just Deserialize_(), should | |
405 // support taking in an allocator. | |
406 template <typename T> | |
407 static void Run(typename WrapperTraits<StructPtr<T>>::DataType input, | |
408 StructPtr<T>* output) { | |
409 if (input) { | |
410 *output = T::New(); | |
411 Deserialize_(input, output->get()); | |
412 } | |
413 } | |
414 | |
415 template <typename T> | |
416 static void Run(typename WrapperTraits<InlinedStructPtr<T>>::DataType input, | |
417 InlinedStructPtr<T>* output) { | |
418 if (input) { | |
419 *output = T::New(); | |
420 Deserialize_(input, output->get()); | |
421 } | |
422 } | |
423 }; | |
424 }; | |
425 | |
426 // Handles serialization and deserialization of arrays of unions. | |
427 template <typename U, typename U_Data> | |
428 struct ArraySerializer<U, U_Data, true> { | |
429 static size_t GetSerializedSize(const Array<U>& input) { | |
430 size_t size = sizeof(Array_Data<U_Data>); | |
431 for (size_t i = 0; i < input.size(); ++i) { | |
432 // GetSerializedSize_ will account for both the data in the union and the | |
433 // space in the array used to hold the union. | |
434 size += GetSerializedSize_(input[i]); | |
435 } | |
436 return size; | |
437 } | |
438 | |
439 template <typename Iterator> | |
440 static ValidationError SerializeElements( | |
441 Iterator it, | |
442 size_t num_elements, | |
443 Buffer* buf, | |
444 Array_Data<U_Data>* output, | |
445 const ArrayValidateParams* validate_params) { | |
446 for (size_t i = 0; i < num_elements; ++i, ++it) { | |
447 U_Data* result = output->storage() + i; | |
448 auto retval = SerializeUnion_(it->get(), buf, &result); | |
449 if (retval != ValidationError::NONE) | |
450 return retval; | |
451 if (!validate_params->element_is_nullable && output->at(i).is_null()) { | |
452 MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( | |
453 | |
454 ValidationError::UNEXPECTED_NULL_POINTER, | |
455 MakeMessageWithArrayIndex("null in array expecting valid unions", | |
456 num_elements, i)); | |
457 return ValidationError::UNEXPECTED_NULL_POINTER; | |
458 } | |
459 } | |
460 | |
461 return ValidationError::NONE; | |
462 } | |
463 | |
464 static void DeserializeElements(Array_Data<U_Data>* input, Array<U>* output) { | |
465 auto result = Array<U>::New(input->size()); | |
466 for (size_t i = 0; i < input->size(); ++i) { | |
467 auto& elem = input->at(i); | |
468 if (!elem.is_null()) { | |
469 using UnwrapedUnionType = typename RemoveStructPtr<U>::type; | |
470 result[i] = UnwrapedUnionType::New(); | |
471 Deserialize_(&elem, result[i].get()); | |
472 } | |
473 } | |
474 output->Swap(&result); | |
475 } | |
476 }; | |
477 | |
478 } // namespace internal | |
479 | |
480 template <typename E> | |
481 inline size_t GetSerializedSize_(const Array<E>& input) { | |
482 if (!input) | |
483 return 0; | |
484 using F = typename internal::WrapperTraits<E>::DataType; | |
485 return internal::ArraySerializer<E, F>::GetSerializedSize(input); | |
486 } | |
487 | |
488 // SerializeArray_ will return ValidationError::NONE on success and set | |
489 // |output| accordingly. On failure, |input| will be partially serialized into | |
490 // |output| up until an error occurs (which is propagated up and returned by | |
491 // SerializeArray_), in which case |buf| is also partially consumed. | |
492 template <typename E, typename F> | |
493 inline internal::ValidationError SerializeArray_( | |
494 Array<E>* input, | |
495 internal::Buffer* buf, | |
496 internal::Array_Data<F>** output, | |
497 const internal::ArrayValidateParams* validate_params) { | |
498 MOJO_DCHECK(input); | |
499 if (!*input) { | |
500 // It is up to the caller to make sure the given |Array| is not null if it | |
501 // is not nullable. | |
502 *output = nullptr; | |
503 return internal::ValidationError::NONE; | |
504 } | |
505 | |
506 if (validate_params->expected_num_elements != 0 && | |
507 input->size() != validate_params->expected_num_elements) { | |
508 MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( | |
509 internal::ValidationError::UNEXPECTED_ARRAY_HEADER, | |
510 internal::MakeMessageWithExpectedArraySize( | |
511 "fixed-size array has wrong number of elements", input->size(), | |
512 validate_params->expected_num_elements)); | |
513 return internal::ValidationError::UNEXPECTED_ARRAY_HEADER; | |
514 } | |
515 | |
516 internal::Array_Data<F>* result = | |
517 internal::Array_Data<F>::New(input->size(), buf); | |
518 auto retval = internal::ArraySerializer<E, F>::SerializeElements( | |
519 input->begin(), input->size(), buf, result, validate_params); | |
520 if (retval != internal::ValidationError::NONE) | |
521 return retval; | |
522 | |
523 *output = result; | |
524 return internal::ValidationError::NONE; | |
525 } | |
526 | |
527 template <typename E, typename F> | |
528 inline void Deserialize_(internal::Array_Data<F>* input, Array<E>* output) { | |
529 if (input) { | |
530 internal::ArraySerializer<E, F>::DeserializeElements(input, output); | |
531 } else { | |
532 output->reset(); | |
533 } | |
534 } | |
535 | |
536 } // namespace mojo | |
537 | |
538 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ | |
OLD | NEW |