Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(102)

Side by Side Diff: mojo/public/cpp/bindings/lib/array_serialization_traits.h

Issue 1953493002: Mojo C++ bindings: custom type mapping for array - part 2 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@21_simplify
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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_
OLDNEW
« no previous file with comments | « mojo/public/cpp/bindings/lib/array_serialization.h ('k') | mojo/public/cpp/bindings/lib/map_serialization.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698