OLD | NEW |
| (Empty) |
1 // Copyright 2016 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_TRAITS_H_ | |
6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_TRAITS_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/lib/array_internal.h" | |
18 #include "mojo/public/cpp/bindings/lib/serialization_forward.h" | |
19 #include "mojo/public/cpp/bindings/lib/template_util.h" | |
20 #include "mojo/public/cpp/bindings/lib/validation_errors.h" | |
21 | |
22 namespace WTF { | |
23 class String; | |
24 } | |
25 | |
26 namespace mojo { | |
27 namespace internal { | |
28 | |
29 enum class ArraySerializerType { | |
30 BOOLEAN, | |
31 // Except boolean. | |
32 POD, | |
33 HANDLE, | |
34 POINTER, | |
35 UNION | |
36 }; | |
37 | |
38 template <typename T> | |
39 struct GetArraySerializerType { | |
40 static const ArraySerializerType value = | |
41 IsUnionDataType<T>::value | |
42 ? ArraySerializerType::UNION | |
43 : (std::is_pointer<T>::value | |
44 ? ArraySerializerType::POINTER | |
45 : (IsHandle<T>::value ? ArraySerializerType::HANDLE | |
46 : (std::is_same<T, bool>::value | |
47 ? ArraySerializerType::BOOLEAN | |
48 : ArraySerializerType::POD))); | |
49 }; | |
50 | |
51 template <typename MojomType, | |
52 typename UserType, | |
53 ArraySerializerType type = | |
54 GetArraySerializerType<typename MojomType::Data_::Element>::value> | |
55 struct ArraySerializer; | |
56 | |
57 // Handles serialization and deserialization of arrays of pod types. | |
58 template <typename MojomType, typename UserType> | |
59 struct ArraySerializer<MojomType, UserType, ArraySerializerType::POD> { | |
60 using Data = typename MojomType::Data_; | |
61 using DataElement = typename Data::Element; | |
62 using Element = typename MojomType::Element; | |
63 using Traits = ArrayTraits<UserType>; | |
64 using UserElement = typename Traits::Element; | |
65 | |
66 static_assert(sizeof(Element) == sizeof(DataElement), | |
67 "Incorrect array serializer"); | |
68 static_assert(std::is_same<Element, UserElement>::value, | |
69 "Incorrect array serializer"); | |
70 | |
71 static size_t GetSerializedSize(const UserType& input, | |
72 SerializationContext* context) { | |
73 return sizeof(Data) + Align(Traits::GetSize(input) * sizeof(DataElement)); | |
74 } | |
75 | |
76 static void SerializeElements(UserType input, | |
77 Buffer* buf, | |
78 Data* output, | |
79 const ArrayValidateParams* validate_params, | |
80 SerializationContext* context) { | |
81 DCHECK(!validate_params->element_is_nullable) | |
82 << "Primitive type should be non-nullable"; | |
83 DCHECK(!validate_params->element_validate_params) | |
84 << "Primitive type should not have array validate params"; | |
85 | |
86 if (Traits::GetSize(input)) { | |
87 memcpy(output->storage(), Traits::GetData(input), | |
88 Traits::GetSize(input) * sizeof(DataElement)); | |
89 } | |
90 } | |
91 | |
92 static bool DeserializeElements(Data* input, | |
93 UserType* output, | |
94 SerializationContext* context) { | |
95 Traits::Resize(*output, input->size()); | |
96 if (input->size()) { | |
97 memcpy(Traits::GetData(*output), input->storage(), | |
98 input->size() * sizeof(DataElement)); | |
99 } | |
100 return true; | |
101 } | |
102 }; | |
103 | |
104 // Serializes and deserializes arrays of bools. | |
105 template <typename MojomType, typename UserType> | |
106 struct ArraySerializer<MojomType, UserType, ArraySerializerType::BOOLEAN> { | |
107 using Traits = ArrayTraits<UserType>; | |
108 using Data = typename MojomType::Data_; | |
109 | |
110 static_assert(std::is_same<bool, typename UserType::Element>::value, | |
111 "Incorrect array serializer"); | |
112 | |
113 static size_t GetSerializedSize(const UserType& input, | |
114 SerializationContext* context) { | |
115 return sizeof(Data) + Align((Traits::GetSize(input) + 7) / 8); | |
116 } | |
117 | |
118 static void SerializeElements(UserType input, | |
119 Buffer* buf, | |
120 Data* output, | |
121 const ArrayValidateParams* validate_params, | |
122 SerializationContext* context) { | |
123 DCHECK(!validate_params->element_is_nullable) | |
124 << "Primitive type should be non-nullable"; | |
125 DCHECK(!validate_params->element_validate_params) | |
126 << "Primitive type should not have array validate params"; | |
127 | |
128 // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? | |
129 size_t size = Traits::GetSize(input); | |
130 for (size_t i = 0; i < size; ++i) | |
131 output->at(i) = Traits::GetAt(input, i); | |
132 } | |
133 static bool DeserializeElements(Data* input, | |
134 UserType* output, | |
135 SerializationContext* context) { | |
136 Traits::Resize(*output, input->size()); | |
137 // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? | |
138 for (size_t i = 0; i < input->size(); ++i) | |
139 Traits::GetAt(*output, i) = input->at(i); | |
140 return true; | |
141 } | |
142 }; | |
143 | |
144 // Serializes and deserializes arrays of handles. | |
145 template <typename MojomType, typename UserType> | |
146 struct ArraySerializer<MojomType, UserType, ArraySerializerType::HANDLE> { | |
147 using Data = typename MojomType::Data_; | |
148 using DataElement = typename Data::Element; | |
149 using Element = typename MojomType::Element; | |
150 using Traits = ArrayTraits<UserType>; | |
151 using UserElement = typename Traits::Element; | |
152 | |
153 static_assert(std::is_same<Element, UserElement>::value, | |
154 "Incorrect array serializer"); | |
155 | |
156 static size_t GetSerializedSize(const UserType& input, | |
157 SerializationContext* context) { | |
158 return sizeof(Data) + Align(Traits::GetSize(input) * sizeof(DataElement)); | |
159 } | |
160 | |
161 static void SerializeElements(UserType input, | |
162 Buffer* buf, | |
163 Data* output, | |
164 const ArrayValidateParams* validate_params, | |
165 SerializationContext* context) { | |
166 DCHECK(!validate_params->element_validate_params) | |
167 << "Handle type should not have array validate params"; | |
168 | |
169 size_t size = Traits::GetSize(input); | |
170 for (size_t i = 0; i < size; ++i) { | |
171 // Transfer ownership of the handle. | |
172 output->at(i) = | |
173 context->handles.AddHandle(Traits::GetAt(input, i).release()); | |
174 MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( | |
175 !validate_params->element_is_nullable && !output->at(i).is_valid(), | |
176 VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, | |
177 MakeMessageWithArrayIndex( | |
178 "invalid handle in array expecting valid handles", size, i)); | |
179 } | |
180 } | |
181 static bool DeserializeElements(Data* input, | |
182 UserType* output, | |
183 SerializationContext* context) { | |
184 using HandleType = typename Element::RawHandleType; | |
185 Traits::Resize(*output, input->size()); | |
186 for (size_t i = 0; i < input->size(); ++i) { | |
187 Traits::GetAt(*output, i) = MakeScopedHandle(HandleType( | |
188 context->handles.TakeHandle(input->at(i)).value())); | |
189 } | |
190 return true; | |
191 } | |
192 }; | |
193 | |
194 // This template must only apply to pointer mojo entity (strings, structs, | |
195 // arrays and maps). | |
196 template <typename MojomType, typename UserType> | |
197 struct ArraySerializer<MojomType, UserType, ArraySerializerType::POINTER> { | |
198 using Data = typename MojomType::Data_; | |
199 using DataElement = typename Data::Element; | |
200 using Element = typename MojomType::Element; | |
201 using Traits = ArrayTraits<UserType>; | |
202 using UserElement = typename Traits::Element; | |
203 | |
204 static size_t GetSerializedSize(const UserType& input, | |
205 SerializationContext* context) { | |
206 size_t element_count = Traits::GetSize(input); | |
207 size_t size = | |
208 sizeof(Data) + | |
209 element_count * | |
210 sizeof(Pointer<typename std::remove_pointer<DataElement>::type>); | |
211 for (size_t i = 0; i < element_count; ++i) | |
212 size += GetSerializedSize_(Traits::GetAt(input, i), context); | |
213 return size; | |
214 } | |
215 | |
216 static void SerializeElements(UserType input, | |
217 Buffer* buf, | |
218 Data* output, | |
219 const ArrayValidateParams* validate_params, | |
220 SerializationContext* context) { | |
221 size_t size = Traits::GetSize(input); | |
222 for (size_t i = 0; i < size; ++i) { | |
223 DataElement element; | |
224 SerializeCaller<Element>::Run( | |
225 std::move(Traits::GetAt(input, i)), buf, &element, | |
226 validate_params->element_validate_params, context); | |
227 output->at(i) = element; | |
228 MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( | |
229 !validate_params->element_is_nullable && !element, | |
230 VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, | |
231 MakeMessageWithArrayIndex("null in array expecting valid pointers", | |
232 size, i)); | |
233 } | |
234 } | |
235 static bool DeserializeElements(Data* input, | |
236 UserType* output, | |
237 SerializationContext* context) { | |
238 bool success = true; | |
239 Traits::Resize(*output, input->size()); | |
240 for (size_t i = 0; i < input->size(); ++i) { | |
241 // Note that we rely on complete deserialization taking place in order to | |
242 // transfer ownership of all encoded handles. Therefore we don't | |
243 // short-circuit on failure here. | |
244 if (!Deserialize_(input->at(i), &Traits::GetAt(*output, i), context)) | |
245 success = false; | |
246 } | |
247 return success; | |
248 } | |
249 | |
250 private: | |
251 template <typename T, | |
252 bool is_array = IsSpecializationOf<Array, T>::value || | |
253 IsSpecializationOf<WTFArray, T>::value, | |
254 bool is_string = std::is_same<T, String>::value || | |
255 std::is_same<T, WTF::String>::value> | |
256 struct SerializeCaller { | |
257 static void Run(T input, | |
258 Buffer* buf, | |
259 DataElement* output, | |
260 const ArrayValidateParams* validate_params, | |
261 SerializationContext* context) { | |
262 DCHECK(!validate_params) | |
263 << "Struct type should not have array validate params"; | |
264 | |
265 Serialize_(std::move(input), buf, output, context); | |
266 } | |
267 }; | |
268 | |
269 template <typename T> | |
270 struct SerializeCaller<T, true, false> { | |
271 static void Run(T input, | |
272 Buffer* buf, | |
273 DataElement* output, | |
274 const ArrayValidateParams* validate_params, | |
275 SerializationContext* context) { | |
276 SerializeArray_(std::move(input), buf, output, validate_params, context); | |
277 } | |
278 }; | |
279 | |
280 template <typename T, typename U> | |
281 struct SerializeCaller<Map<T, U>, false, false> { | |
282 static void Run(Map<T, U> input, | |
283 Buffer* buf, | |
284 DataElement* output, | |
285 const ArrayValidateParams* validate_params, | |
286 SerializationContext* context) { | |
287 SerializeMap_(std::move(input), buf, output, validate_params, context); | |
288 } | |
289 }; | |
290 | |
291 template <typename T> | |
292 struct SerializeCaller<T, false, true> { | |
293 static void Run(const T& input, | |
294 Buffer* buf, | |
295 DataElement* output, | |
296 const ArrayValidateParams* validate_params, | |
297 SerializationContext* context) { | |
298 DCHECK(validate_params && !validate_params->element_validate_params && | |
299 !validate_params->element_is_nullable && | |
300 validate_params->expected_num_elements == 0) | |
301 << "String type has unexpected array validate params"; | |
302 | |
303 Serialize_(input, buf, output, context); | |
304 } | |
305 }; | |
306 }; | |
307 | |
308 // Handles serialization and deserialization of arrays of unions. | |
309 template <typename MojomType, typename UserType> | |
310 struct ArraySerializer<MojomType, UserType, ArraySerializerType::UNION> { | |
311 using Data = typename MojomType::Data_; | |
312 using DataElement = typename Data::Element; | |
313 using Element = typename MojomType::Element; | |
314 using Traits = ArrayTraits<UserType>; | |
315 using UserElement = typename Traits::Element; | |
316 | |
317 static_assert(std::is_same<Element, UserElement>::value, | |
318 "Incorrect array serializer"); | |
319 | |
320 static size_t GetSerializedSize(const UserType& input, | |
321 SerializationContext* context) { | |
322 size_t element_count = Traits::GetSize(input); | |
323 size_t size = sizeof(Data); | |
324 for (size_t i = 0; i < element_count; ++i) { | |
325 // Call GetSerializedSize_ with |inlined| set to false, so that it will | |
326 // account for both the data in the union and the space in the array used | |
327 // to hold the union. | |
328 size += GetSerializedSize_(Traits::GetAt(input, i), false, context); | |
329 } | |
330 return size; | |
331 } | |
332 | |
333 static void SerializeElements(UserType input, | |
334 Buffer* buf, | |
335 Data* output, | |
336 const ArrayValidateParams* validate_params, | |
337 SerializationContext* context) { | |
338 size_t size = Traits::GetSize(input); | |
339 for (size_t i = 0; i < size; ++i) { | |
340 DataElement* result = output->storage() + i; | |
341 SerializeUnion_(std::move(Traits::GetAt(input, i)), buf, &result, true, | |
342 context); | |
343 MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( | |
344 !validate_params->element_is_nullable && output->at(i).is_null(), | |
345 VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, | |
346 MakeMessageWithArrayIndex("null in array expecting valid unions", | |
347 size, i)); | |
348 } | |
349 } | |
350 | |
351 static bool DeserializeElements(Data* input, | |
352 UserType* output, | |
353 SerializationContext* context) { | |
354 bool success = true; | |
355 Traits::Resize(*output, input->size()); | |
356 for (size_t i = 0; i < input->size(); ++i) { | |
357 // Note that we rely on complete deserialization taking place in order to | |
358 // transfer ownership of all encoded handles. Therefore we don't | |
359 // short-circuit on failure here. | |
360 if (!Deserialize_(&input->at(i), &Traits::GetAt(*output, i), context)) | |
361 success = false; | |
362 } | |
363 return success; | |
364 } | |
365 }; | |
366 | |
367 // Another layer of abstraction to switch between standard mojom type | |
368 // serializers and native-only serializers. | |
369 template <typename MojomType, | |
370 typename UserType, | |
371 bool use_native = | |
372 ShouldUseNativeSerializer<typename MojomType::Element>::value> | |
373 struct ArraySerializationStrategy; | |
374 | |
375 // Serialization strategy for standard mojom types. This branches further | |
376 // by choosing an ArraySerializer specialization from above. | |
377 template <typename MojomType, typename UserType> | |
378 struct ArraySerializationStrategy<MojomType, UserType, false> { | |
379 using Serializer = ArraySerializer<MojomType, UserType>; | |
380 using Traits = ArrayTraits<UserType>; | |
381 using Data = typename MojomType::Data_; | |
382 | |
383 static size_t GetSerializedSize(const UserType& input, | |
384 SerializationContext* context) { | |
385 DCHECK(!Traits::IsNull(input)); | |
386 return Serializer::GetSerializedSize(input, context); | |
387 } | |
388 | |
389 static void Serialize(UserType input, | |
390 Buffer* buf, | |
391 Data** output, | |
392 const ArrayValidateParams* validate_params, | |
393 SerializationContext* context) { | |
394 DCHECK(!Traits::IsNull(input)); | |
395 Data* result = Data::New(Traits::GetSize(input), buf); | |
396 if (result) { | |
397 Serializer::SerializeElements(std::move(input), buf, result, | |
398 validate_params, context); | |
399 } | |
400 *output = result; | |
401 } | |
402 | |
403 static bool Deserialize(Data* input, | |
404 UserType* output, | |
405 SerializationContext* context) { | |
406 DCHECK(input); | |
407 return Serializer::DeserializeElements(input, output, context); | |
408 } | |
409 }; | |
410 | |
411 // Serialization for arrays of native-only types, which are opaquely serialized | |
412 // as arrays of uint8_t arrays. | |
413 template <typename MojomType, typename UserType> | |
414 struct ArraySerializationStrategy<MojomType, UserType, true> { | |
415 using Traits = ArrayTraits<UserType>; | |
416 using Data = typename MojomType::Data_; | |
417 using Element = typename MojomType::Element; | |
418 | |
419 static_assert( | |
420 std::is_same<Data, Array_Data<NativeStruct_Data*>>::value, | |
421 "Mismatched types for serializing array of native-only structs."); | |
422 | |
423 static size_t GetSerializedSize(const UserType& input, | |
424 SerializationContext* context) { | |
425 DCHECK(!Traits::IsNull(input)); | |
426 | |
427 size_t element_count = Traits::GetSize(input); | |
428 DCHECK_LE(element_count, std::numeric_limits<uint32_t>::max()); | |
429 size_t size = ArrayDataTraits<NativeStruct_Data*>::GetStorageSize( | |
430 static_cast<uint32_t>(element_count)); | |
431 for (size_t i = 0; i < element_count; ++i) { | |
432 size_t element_size = | |
433 PrepareToSerialize<NativeStructPtr>(Traits::GetAt(input, i), context); | |
434 DCHECK_LT(element_size, std::numeric_limits<uint32_t>::max()); | |
435 size += static_cast<uint32_t>(element_size); | |
436 } | |
437 return size; | |
438 } | |
439 | |
440 static void Serialize(UserType input, | |
441 Buffer* buf, | |
442 Data** output, | |
443 const ArrayValidateParams* validate_params, | |
444 SerializationContext* context) { | |
445 DCHECK(!Traits::IsNull(input)); | |
446 DCHECK(validate_params); | |
447 // TODO(rockot): We may want to support nullable (i.e. std::unique_ptr<T>) | |
448 // elements here. | |
449 DCHECK(!validate_params->element_is_nullable); | |
450 size_t element_count = Traits::GetSize(input); | |
451 Data* result = Data::New(element_count, buf); | |
452 for (size_t i = 0; i < element_count; ++i) | |
453 internal::Serialize<NativeStructPtr>(Traits::GetAt(input, i), buf, | |
454 &result->at(i), context); | |
455 *output = result; | |
456 } | |
457 | |
458 static bool Deserialize(Data* input, | |
459 UserType* output, | |
460 SerializationContext* context) { | |
461 DCHECK(input); | |
462 | |
463 Traits::Resize(*output, input->size()); | |
464 bool success = true; | |
465 for (size_t i = 0; i < input->size(); ++i) { | |
466 // We don't short-circuit on failure since we can't know what the native | |
467 // type's ParamTraits' expectations are. | |
468 if (!internal::Deserialize<NativeStructPtr>( | |
469 input->at(i), &Traits::GetAt(*output, i), context)) | |
470 success = false; | |
471 } | |
472 return success; | |
473 } | |
474 }; | |
475 | |
476 template <typename MojomType, typename UserType> | |
477 struct ArraySerializationImpl { | |
478 using Traits = ArrayTraits<UserType>; | |
479 using Strategy = ArraySerializationStrategy<MojomType, UserType>; | |
480 | |
481 static size_t GetSerializedSize(const UserType& input, | |
482 SerializationContext* context) { | |
483 if (Traits::IsNull(input)) | |
484 return 0; | |
485 return Strategy::GetSerializedSize(input, context); | |
486 } | |
487 | |
488 static void Serialize(UserType input, | |
489 internal::Buffer* buf, | |
490 typename MojomType::Data_** output, | |
491 const internal::ArrayValidateParams* validate_params, | |
492 SerializationContext* context) { | |
493 if (!Traits::IsNull(input)) { | |
494 MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( | |
495 validate_params->expected_num_elements != 0 && | |
496 Traits::GetSize(input) != validate_params->expected_num_elements, | |
497 internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER, | |
498 internal::MakeMessageWithExpectedArraySize( | |
499 "fixed-size array has wrong number of elements", | |
500 Traits::GetSize(input), validate_params->expected_num_elements)); | |
501 Strategy::Serialize(std::move(input), buf, output, validate_params, | |
502 context); | |
503 } else { | |
504 *output = nullptr; | |
505 } | |
506 } | |
507 | |
508 static bool Deserialize(typename MojomType::Data_* input, | |
509 UserType* output, | |
510 internal::SerializationContext* context) { | |
511 if (input) | |
512 return Strategy::Deserialize(input, output, context); | |
513 Traits::SetToNull(*output); | |
514 return true; | |
515 } | |
516 }; | |
517 | |
518 } // namespace internal | |
519 | |
520 } // namespace mojo | |
521 | |
522 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_TRAITS_H_ | |
OLD | NEW |