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