QueueParamTraits.h (24599B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: sw=2 ts=4 et : 3 */ 4 /* This Source Code Form is subject to the terms of the Mozilla Public 5 * License, v. 2.0. If a copy of the MPL was not distributed with this 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 7 8 #ifndef _QUEUEPARAMTRAITS_H_ 9 #define _QUEUEPARAMTRAITS_H_ 1 10 11 #include "WebGLTypes.h" 12 #include "ipc/EnumSerializer.h" 13 #include "mozilla/Assertions.h" 14 #include "mozilla/IntegerRange.h" 15 #include "mozilla/Logging.h" 16 #include "mozilla/TimeStamp.h" 17 #include "mozilla/gfx/2D.h" 18 #include "mozilla/ipc/ProtocolUtils.h" 19 #include "nsExceptionHandler.h" 20 #include "nsString.h" 21 22 namespace mozilla::webgl { 23 24 template <typename T> 25 struct RemoveCVR { 26 using Type = 27 typename std::remove_reference<typename std::remove_cv<T>::type>::type; 28 }; 29 30 /** 31 * QueueParamTraits provide the user with a way to implement PCQ argument 32 * (de)serialization. It uses a PcqView, which permits the system to 33 * abandon all changes to the underlying PCQ if any operation fails. 34 * 35 * The transactional nature of PCQ operations make the ideal behavior a bit 36 * complex. Since the PCQ has a fixed amount of memory available to it, 37 * TryInsert operations operations are expected to sometimes fail and be 38 * re-issued later. We want these failures to be inexpensive. The same 39 * goes for TryRemove, which fails when there isn't enough data in 40 * the queue yet for them to complete. 41 * 42 * Their expected interface is: 43 * 44 * template<> struct QueueParamTraits<typename RemoveCVR<Arg>::Type> { 45 * // Write data from aArg into the PCQ. 46 * static QueueStatus Write(ProducerView& aProducerView, const Arg& aArg) 47 * {...}; 48 * 49 * // Read data from the PCQ into aArg, or just skip the data if aArg is null. 50 * static QueueStatus Read(ConsumerView& aConsumerView, Arg* aArg) {...} 51 * }; 52 */ 53 template <typename Arg> 54 struct QueueParamTraits; // Todo: s/QueueParamTraits/SizedParamTraits/ 55 56 template <typename T> 57 inline Range<T> AsRange(T* const begin, T* const end) { 58 const auto size = MaybeAs<size_t>(end - begin); 59 MOZ_RELEASE_ASSERT(size); 60 return {begin, *size}; 61 } 62 63 // - 64 // BytesAlwaysValidT 65 66 template <class T> 67 struct BytesAlwaysValidT { 68 using non_cv = typename std::remove_cv<T>::type; 69 static constexpr bool value = 70 std::is_arithmetic<T>::value && !std::is_same<non_cv, bool>::value; 71 }; 72 static_assert(BytesAlwaysValidT<float>::value); 73 static_assert(!BytesAlwaysValidT<bool>::value); 74 static_assert(!BytesAlwaysValidT<const bool>::value); 75 static_assert(!BytesAlwaysValidT<int*>::value); 76 static_assert(BytesAlwaysValidT<intptr_t>::value); 77 78 template <class T, size_t N> 79 struct BytesAlwaysValidT<std::array<T, N>> { 80 static constexpr bool value = BytesAlwaysValidT<T>::value; 81 }; 82 static_assert(BytesAlwaysValidT<std::array<int, 4>>::value); 83 static_assert(!BytesAlwaysValidT<std::array<bool, 4>>::value); 84 85 template <class T, size_t N> 86 struct BytesAlwaysValidT<T[N]> { 87 static constexpr bool value = BytesAlwaysValidT<T>::value; 88 }; 89 static_assert(BytesAlwaysValidT<int[4]>::value); 90 static_assert(!BytesAlwaysValidT<bool[4]>::value); 91 92 // - 93 94 template <> 95 struct BytesAlwaysValidT<webgl::UniformDataVal> { 96 static constexpr bool value = true; 97 }; 98 template <> 99 struct BytesAlwaysValidT<const webgl::UniformDataVal> { 100 static constexpr bool value = true; 101 }; 102 103 // - 104 105 /** 106 * Used to give QueueParamTraits a way to write to the Producer without 107 * actually altering it, in case the transaction fails. 108 * THis object maintains the error state of the transaction and 109 * discards commands issued after an error is encountered. 110 */ 111 template <typename _Producer> 112 class ProducerView { 113 public: 114 using Producer = _Producer; 115 116 explicit ProducerView(Producer* aProducer) : mProducer(aProducer) {} 117 118 template <typename T> 119 bool WriteFromRange(const Range<const T>& src) { 120 static_assert(BytesAlwaysValidT<T>::value); 121 if (MOZ_LIKELY(mOk)) { 122 mOk &= mProducer->WriteFromRange(src); 123 } 124 return mOk; 125 } 126 127 /** 128 * Copy bytes from aBuffer to the producer if there is enough room. 129 * aBufferSize must not be 0. 130 */ 131 template <typename T> 132 inline bool Write(const T* begin, const T* end) { 133 MOZ_RELEASE_ASSERT(begin <= end); 134 return WriteFromRange(AsRange(begin, end)); 135 } 136 137 /** 138 * Serialize aArg using Arg's QueueParamTraits. 139 */ 140 template <typename Arg> 141 bool WriteParam(const Arg& aArg) { 142 return mozilla::webgl::QueueParamTraits< 143 typename RemoveCVR<Arg>::Type>::Write(*this, aArg); 144 } 145 146 bool Ok() const { return mOk; } 147 148 private: 149 Producer* const mProducer; 150 bool mOk = true; 151 }; 152 153 /** 154 * Used to give QueueParamTraits a way to read from the Consumer without 155 * actually altering it, in case the transaction fails. 156 */ 157 template <typename _Consumer> 158 class ConsumerView { 159 public: 160 using Consumer = _Consumer; 161 162 explicit ConsumerView(Consumer* aConsumer) : mConsumer(aConsumer) {} 163 164 /** 165 * Read bytes from the consumer if there is enough data. aBuffer may 166 * be null (in which case the data is skipped) 167 */ 168 template <typename T> 169 inline bool Read(T* const destBegin, T* const destEnd) { 170 MOZ_ASSERT(destBegin); 171 MOZ_RELEASE_ASSERT(destBegin <= destEnd); 172 173 const auto dest = AsRange(destBegin, destEnd); 174 const auto view = ReadRange<T>(dest.length()); 175 if (MOZ_LIKELY(view)) { 176 const auto byteSize = ByteSize(dest); 177 if (MOZ_LIKELY(byteSize)) { 178 memcpy(dest.begin().get(), view->begin().get(), byteSize); 179 } 180 } 181 return mOk; 182 } 183 184 /// Return a view wrapping the shmem. 185 template <typename T> 186 inline Maybe<Range<const T>> ReadRange(const size_t elemCount) { 187 static_assert(BytesAlwaysValidT<T>::value); 188 if (MOZ_UNLIKELY(!mOk)) return {}; 189 const auto view = mConsumer->template ReadRange<T>(elemCount); 190 mOk &= bool(view); 191 return view; 192 } 193 194 /** 195 * Deserialize aArg using Arg's QueueParamTraits. 196 * If the return value is not Success then aArg is not changed. 197 */ 198 template <typename Arg> 199 bool ReadParam(Arg* aArg) { 200 MOZ_ASSERT(aArg); 201 return mozilla::webgl::QueueParamTraits<std::remove_cv_t<Arg>>::Read(*this, 202 aArg); 203 } 204 205 bool Ok() const { return mOk; } 206 207 private: 208 Consumer* const mConsumer; 209 bool mOk = true; 210 }; 211 212 // - 213 214 template <typename Arg> 215 struct QueueParamTraits { 216 template <typename ProducerView> 217 static bool Write(ProducerView& aProducerView, const Arg& aArg) { 218 static_assert(BytesAlwaysValidT<Arg>::value, 219 "No QueueParamTraits specialization was found for this type " 220 "and it does not satisfy BytesAlwaysValid."); 221 // Write self as binary 222 const auto pArg = &aArg; 223 return aProducerView.Write(pArg, pArg + 1); 224 } 225 226 template <typename ConsumerView> 227 static bool Read(ConsumerView& aConsumerView, Arg* aArg) { 228 static_assert(BytesAlwaysValidT<Arg>::value, 229 "No QueueParamTraits specialization was found for this type " 230 "and it does not satisfy BytesAlwaysValid."); 231 // Read self as binary 232 return aConsumerView.Read(aArg, aArg + 1); 233 } 234 }; 235 236 // --------------------------------------------------------------- 237 238 template <> 239 struct QueueParamTraits<bool> { 240 using ParamType = bool; 241 242 template <typename U> 243 static auto Write(ProducerView<U>& aProducerView, const ParamType& aArg) { 244 uint8_t temp = aArg ? 1 : 0; 245 return aProducerView.WriteParam(temp); 246 } 247 248 template <typename U> 249 static auto Read(ConsumerView<U>& aConsumerView, ParamType* aArg) { 250 uint8_t temp; 251 if (aConsumerView.ReadParam(&temp)) { 252 MOZ_ASSERT(temp == 1 || temp == 0); 253 *aArg = temp ? true : false; 254 } 255 return aConsumerView.Ok(); 256 } 257 }; 258 259 // --------------------------------------------------------------- 260 261 template <class T> 262 struct QueueParamTraits_IsEnumCase { 263 template <typename ProducerView> 264 static bool Write(ProducerView& aProducerView, const T& aArg) { 265 MOZ_ASSERT(IsEnumCase(aArg)); 266 const auto shadow = static_cast<std::underlying_type_t<T>>(aArg); 267 aProducerView.WriteParam(shadow); 268 return true; 269 } 270 271 template <typename ConsumerView> 272 static bool Read(ConsumerView& aConsumerView, T* aArg) { 273 auto shadow = std::underlying_type_t<T>{}; 274 aConsumerView.ReadParam(&shadow); 275 const auto e = AsEnumCase<T>(shadow); 276 if (!e) return false; 277 *aArg = *e; 278 return true; 279 } 280 }; 281 282 // --------------------------------------------------------------- 283 284 // We guarantee our robustness via these requirements: 285 // * Object.MutTiedFields() gives us a tuple, 286 // * where the combined sizeofs all field types sums to sizeof(Object), 287 // * (thus we know we are exhaustively listing all fields) 288 // * where feeding each field back into ParamTraits succeeds, 289 // * and ParamTraits is only automated for BytesAlwaysValidT<T> types. 290 // (BytesAlwaysValidT rejects bool and enum types, and only accepts int/float 291 // types, or array or std::arrays of such types) 292 // (Yes, bit-field fields are rejected by MutTiedFields too) 293 294 template <class T> 295 struct QueueParamTraits_TiedFields { 296 template <typename ProducerView> 297 static bool Write(ProducerView& aProducerView, const T& aArg) { 298 const auto fields = TiedFields(aArg); 299 static_assert(AreAllBytesTiedFields<T>(), 300 "Are there missing fields or padding between fields?"); 301 302 bool ok = true; 303 MapTuple(fields, [&](const auto& field) { 304 ok &= aProducerView.WriteParam(field); 305 return true; 306 }); 307 return ok; 308 } 309 310 template <typename ConsumerView> 311 static bool Read(ConsumerView& aConsumerView, T* aArg) { 312 const auto fields = TiedFields(*aArg); 313 static_assert(AreAllBytesTiedFields<T>()); 314 315 bool ok = true; 316 MapTuple(fields, [&](auto& field) { 317 ok &= aConsumerView.ReadParam(&field); 318 return true; 319 }); 320 return ok; 321 } 322 }; 323 324 // --------------------------------------------------------------- 325 326 // Adapted from IPC::EnumSerializer, this class safely handles enum values, 327 // validating that they are in range using the same EnumValidators as IPDL 328 // (namely ContiguousEnumValidator and ContiguousEnumValidatorInclusive). 329 template <typename E, typename EnumValidator> 330 struct EnumSerializer { 331 using ParamType = E; 332 using DataType = typename std::underlying_type<E>::type; 333 334 template <typename U> 335 static auto Write(ProducerView<U>& aProducerView, const ParamType& aValue) { 336 MOZ_RELEASE_ASSERT( 337 EnumValidator::IsLegalValue(static_cast<DataType>(aValue))); 338 return aProducerView.WriteParam(DataType(aValue)); 339 } 340 341 template <typename U> 342 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aResult) { 343 DataType value; 344 if (!aConsumerView.ReadParam(&value)) { 345 CrashReporter::RecordAnnotationCString( 346 CrashReporter::Annotation::IPCReadErrorReason, "Bad iter"); 347 return false; 348 } 349 if (!EnumValidator::IsLegalValue(static_cast<DataType>(value))) { 350 CrashReporter::RecordAnnotationCString( 351 CrashReporter::Annotation::IPCReadErrorReason, "Illegal value"); 352 return false; 353 } 354 355 *aResult = ParamType(value); 356 return true; 357 } 358 }; 359 360 using IPC::ContiguousEnumValidator; 361 using IPC::ContiguousEnumValidatorInclusive; 362 363 template <typename E, E MinLegal, E HighBound> 364 struct ContiguousEnumSerializer 365 : EnumSerializer<E, ContiguousEnumValidator<E, MinLegal, HighBound>> {}; 366 367 template <typename E, E MinLegal, E MaxLegal> 368 struct ContiguousEnumSerializerInclusive 369 : EnumSerializer<E, 370 ContiguousEnumValidatorInclusive<E, MinLegal, MaxLegal>> { 371 }; 372 373 // --------------------------------------------------------------- 374 375 template <> 376 struct QueueParamTraits<webgl::TexUnpackBlobDesc> { 377 using ParamType = webgl::TexUnpackBlobDesc; 378 379 template <typename U> 380 static bool Write(ProducerView<U>& view, const ParamType& in) { 381 MOZ_RELEASE_ASSERT(!in.image); 382 MOZ_RELEASE_ASSERT(!in.sd); 383 const bool isDataSurf = bool(in.sourceSurf); 384 if (!view.WriteParam(in.imageTarget) || !view.WriteParam(in.size) || 385 !view.WriteParam(in.srcAlphaType) || !view.WriteParam(in.unpacking) || 386 !view.WriteParam(in.cpuData) || !view.WriteParam(in.pboOffset) || 387 !view.WriteParam(in.structuredSrcSize) || 388 !view.WriteParam(in.applyUnpackTransforms) || 389 !view.WriteParam(isDataSurf)) { 390 return false; 391 } 392 if (isDataSurf) { 393 const RefPtr<gfx::DataSourceSurface> surf = 394 in.sourceSurf->GetDataSurface(); 395 if (!surf) { 396 return false; 397 } 398 gfx::DataSourceSurface::ScopedMap map(surf, gfx::DataSourceSurface::READ); 399 if (!map.IsMapped()) { 400 return false; 401 } 402 const auto& surfSize = surf->GetSize(); 403 const auto stride = *MaybeAs<size_t>(map.GetStride()); 404 if (!view.WriteParam(surfSize) || !view.WriteParam(surf->GetFormat()) || 405 !view.WriteParam(stride)) { 406 return false; 407 } 408 409 const size_t dataSize = stride * surfSize.height; 410 const auto& begin = map.GetData(); 411 const auto range = Range<const uint8_t>{begin, dataSize}; 412 if (!view.WriteFromRange(range)) { 413 return false; 414 } 415 } 416 return true; 417 } 418 419 template <typename U> 420 static bool Read(ConsumerView<U>& view, ParamType* const out) { 421 bool isDataSurf; 422 if (!view.ReadParam(&out->imageTarget) || !view.ReadParam(&out->size) || 423 !view.ReadParam(&out->srcAlphaType) || 424 !view.ReadParam(&out->unpacking) || !view.ReadParam(&out->cpuData) || 425 !view.ReadParam(&out->pboOffset) || 426 !view.ReadParam(&out->structuredSrcSize) || 427 !view.ReadParam(&out->applyUnpackTransforms) || 428 !view.ReadParam(&isDataSurf)) { 429 return false; 430 } 431 if (isDataSurf) { 432 gfx::IntSize surfSize; 433 gfx::SurfaceFormat format; 434 size_t stride; 435 if (!view.ReadParam(&surfSize) || !view.ReadParam(&format) || 436 !view.ReadParam(&stride)) { 437 return false; 438 } 439 if (!CheckedInt32(stride).isValid() || surfSize.IsEmpty()) { 440 return false; 441 } 442 int32_t bpp = BytesPerPixel(format); 443 CheckedInt<size_t> minStride(bpp); 444 minStride *= surfSize.width; 445 if (!minStride.isValid() || minStride.value() <= 0 || 446 stride < minStride.value()) { 447 return false; 448 } 449 CheckedInt<size_t> dataSize(stride); 450 dataSize *= surfSize.height; 451 if (!dataSize.isValid()) { 452 return false; 453 } 454 const auto range = view.template ReadRange<uint8_t>(dataSize.value()); 455 if (!range) return false; 456 457 // DataSourceSurface demands pointer-to-mutable. 458 const auto bytes = const_cast<uint8_t*>(range->begin().get()); 459 out->sourceSurf = gfx::Factory::CreateWrappingDataSourceSurface( 460 bytes, stride, surfSize, format); 461 MOZ_ASSERT(out->sourceSurf); 462 } 463 return true; 464 } 465 }; 466 467 // --------------------------------------------------------------- 468 469 template <> 470 struct QueueParamTraits<nsACString> { 471 using ParamType = nsACString; 472 473 template <typename U> 474 static bool Write(ProducerView<U>& aProducerView, const ParamType& aArg) { 475 if ((!aProducerView.WriteParam(aArg.IsVoid())) || aArg.IsVoid()) { 476 return false; 477 } 478 479 uint32_t len = aArg.Length(); 480 if ((!aProducerView.WriteParam(len)) || (len == 0)) { 481 return false; 482 } 483 484 return aProducerView.Write(aArg.BeginReading(), len); 485 } 486 487 template <typename U> 488 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) { 489 bool isVoid = false; 490 if (!aConsumerView.ReadParam(&isVoid)) { 491 return false; 492 } 493 aArg->SetIsVoid(isVoid); 494 if (isVoid) { 495 return true; 496 } 497 498 uint32_t len = 0; 499 if (!aConsumerView.ReadParam(&len)) { 500 return false; 501 } 502 503 if (len == 0) { 504 *aArg = ""; 505 return true; 506 } 507 508 char* buf = new char[len + 1]; 509 if (!buf) { 510 return false; 511 } 512 if (!aConsumerView.Read(buf, len)) { 513 return false; 514 } 515 buf[len] = '\0'; 516 aArg->Adopt(buf, len); 517 return true; 518 } 519 }; 520 521 template <> 522 struct QueueParamTraits<nsAString> { 523 using ParamType = nsAString; 524 525 template <typename U> 526 static bool Write(ProducerView<U>& aProducerView, const ParamType& aArg) { 527 if ((!aProducerView.WriteParam(aArg.IsVoid())) || (aArg.IsVoid())) { 528 return false; 529 } 530 // DLP: No idea if this includes null terminator 531 uint32_t len = aArg.Length(); 532 if ((!aProducerView.WriteParam(len)) || (len == 0)) { 533 return false; 534 } 535 constexpr const uint32_t sizeofchar = sizeof(typename ParamType::char_type); 536 return aProducerView.Write(aArg.BeginReading(), len * sizeofchar); 537 } 538 539 template <typename U> 540 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) { 541 bool isVoid = false; 542 if (!aConsumerView.ReadParam(&isVoid)) { 543 return false; 544 } 545 aArg->SetIsVoid(isVoid); 546 if (isVoid) { 547 return true; 548 } 549 550 // DLP: No idea if this includes null terminator 551 uint32_t len = 0; 552 if (!aConsumerView.ReadParam(&len)) { 553 return false; 554 } 555 556 if (len == 0) { 557 *aArg = nsString(); 558 return true; 559 } 560 561 uint32_t sizeofchar = sizeof(typename ParamType::char_type); 562 typename ParamType::char_type* buf = nullptr; 563 buf = static_cast<typename ParamType::char_type*>( 564 malloc((len + 1) * sizeofchar)); 565 if (!buf) { 566 return false; 567 } 568 569 if (!aConsumerView.Read(buf, len * sizeofchar)) { 570 return false; 571 } 572 573 buf[len] = L'\0'; 574 aArg->Adopt(buf, len); 575 return true; 576 } 577 }; 578 579 template <> 580 struct QueueParamTraits<nsCString> : public QueueParamTraits<nsACString> { 581 using ParamType = nsCString; 582 }; 583 584 template <> 585 struct QueueParamTraits<nsString> : public QueueParamTraits<nsAString> { 586 using ParamType = nsString; 587 }; 588 589 // --------------------------------------------------------------- 590 591 template <typename NSTArrayType, 592 bool = BytesAlwaysValidT<typename NSTArrayType::value_type>::value> 593 struct NSArrayQueueParamTraits; 594 595 // For ElementTypes that are !BytesAlwaysValidT 596 template <typename _ElementType> 597 struct NSArrayQueueParamTraits<nsTArray<_ElementType>, false> { 598 using ElementType = _ElementType; 599 using ParamType = nsTArray<ElementType>; 600 601 template <typename U> 602 static bool Write(ProducerView<U>& aProducerView, const ParamType& aArg) { 603 aProducerView.WriteParam(aArg.Length()); 604 for (auto& elt : aArg) { 605 aProducerView.WriteParam(elt); 606 } 607 return true; 608 } 609 610 template <typename U> 611 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) { 612 size_t arrayLen; 613 if (!aConsumerView.ReadParam(&arrayLen)) { 614 return false; 615 } 616 617 if (!aArg->AppendElements(arrayLen, fallible)) { 618 return false; 619 } 620 621 for (auto i : IntegerRange(arrayLen)) { 622 ElementType& elt = aArg->ElementAt(i); 623 aConsumerView.ReadParam(elt); 624 } 625 return aConsumerView.Ok(); 626 } 627 }; 628 629 // For ElementTypes that are BytesAlwaysValidT 630 template <typename _ElementType> 631 struct NSArrayQueueParamTraits<nsTArray<_ElementType>, true> { 632 using ElementType = _ElementType; 633 using ParamType = nsTArray<ElementType>; 634 635 // TODO: Are there alignment issues? 636 template <typename U> 637 static bool Write(ProducerView<U>& aProducerView, const ParamType& aArg) { 638 size_t arrayLen = aArg.Length(); 639 aProducerView.WriteParam(arrayLen); 640 return aProducerView.Write(&aArg[0], aArg.Length() * sizeof(ElementType)); 641 } 642 643 template <typename U> 644 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) { 645 size_t arrayLen; 646 if (!aConsumerView.ReadParam(&arrayLen)) { 647 return false; 648 } 649 650 if (!aArg->AppendElements(arrayLen, fallible)) { 651 return false; 652 } 653 654 return aConsumerView.Read(aArg->Elements(), arrayLen * sizeof(ElementType)); 655 } 656 }; 657 658 template <typename ElementType> 659 struct QueueParamTraits<nsTArray<ElementType>> 660 : public NSArrayQueueParamTraits<nsTArray<ElementType>> { 661 using ParamType = nsTArray<ElementType>; 662 }; 663 664 // --------------------------------------------------------------- 665 666 template <typename ArrayType, 667 bool = BytesAlwaysValidT<typename ArrayType::ElementType>::value> 668 struct ArrayQueueParamTraits; 669 670 // For ElementTypes that are !BytesAlwaysValidT 671 template <typename _ElementType, size_t Length> 672 struct ArrayQueueParamTraits<Array<_ElementType, Length>, false> { 673 using ElementType = _ElementType; 674 using ParamType = Array<ElementType, Length>; 675 676 template <typename U> 677 static auto Write(ProducerView<U>& aProducerView, const ParamType& aArg) { 678 for (const auto& elt : aArg) { 679 aProducerView.WriteParam(elt); 680 } 681 return aProducerView.Ok(); 682 } 683 684 template <typename U> 685 static auto Read(ConsumerView<U>& aConsumerView, ParamType* aArg) { 686 for (auto& elt : *aArg) { 687 aConsumerView.ReadParam(elt); 688 } 689 return aConsumerView.Ok(); 690 } 691 }; 692 693 // For ElementTypes that are BytesAlwaysValidT 694 template <typename _ElementType, size_t Length> 695 struct ArrayQueueParamTraits<Array<_ElementType, Length>, true> { 696 using ElementType = _ElementType; 697 using ParamType = Array<ElementType, Length>; 698 699 template <typename U> 700 static auto Write(ProducerView<U>& aProducerView, const ParamType& aArg) { 701 return aProducerView.Write(aArg.begin(), sizeof(ElementType[Length])); 702 } 703 704 template <typename U> 705 static auto Read(ConsumerView<U>& aConsumerView, ParamType* aArg) { 706 return aConsumerView.Read(aArg->begin(), sizeof(ElementType[Length])); 707 } 708 }; 709 710 template <typename ElementType, size_t Length> 711 struct QueueParamTraits<Array<ElementType, Length>> 712 : public ArrayQueueParamTraits<Array<ElementType, Length>> { 713 using ParamType = Array<ElementType, Length>; 714 }; 715 716 // --------------------------------------------------------------- 717 718 template <typename ElementType> 719 struct QueueParamTraits<Maybe<ElementType>> { 720 using ParamType = Maybe<ElementType>; 721 722 template <typename U> 723 static bool Write(ProducerView<U>& aProducerView, const ParamType& aArg) { 724 aProducerView.WriteParam(static_cast<bool>(aArg)); 725 if (aArg) { 726 aProducerView.WriteParam(aArg.ref()); 727 } 728 return aProducerView.Ok(); 729 } 730 731 template <typename U> 732 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) { 733 bool isSome; 734 if (!aConsumerView.ReadParam(&isSome)) { 735 return false; 736 } 737 738 if (!isSome) { 739 aArg->reset(); 740 return true; 741 } 742 743 aArg->emplace(); 744 return aConsumerView.ReadParam(aArg->ptr()); 745 } 746 }; 747 748 // --------------------------------------------------------------- 749 750 template <typename TypeA, typename TypeB> 751 struct QueueParamTraits<std::pair<TypeA, TypeB>> { 752 using ParamType = std::pair<TypeA, TypeB>; 753 754 template <typename U> 755 static bool Write(ProducerView<U>& aProducerView, const ParamType& aArg) { 756 aProducerView.WriteParam(aArg.first()); 757 return aProducerView.WriteParam(aArg.second()); 758 } 759 760 template <typename U> 761 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) { 762 aConsumerView.ReadParam(aArg->first()); 763 return aConsumerView.ReadParam(aArg->second()); 764 } 765 }; 766 767 // - 768 769 template <class... T> 770 struct QueueParamTraits<std::tuple<T...>> { 771 using ParamType = std::tuple<T...>; 772 773 template <typename U> 774 static bool Write(ProducerView<U>& aProducerView, const ParamType& aArg) { 775 bool ok = true; 776 mozilla::MapTuple(aArg, [&](const auto& field) { 777 ok &= aProducerView.WriteParam(field); 778 return true; // ignored 779 }); 780 return ok; 781 } 782 783 template <typename U> 784 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) { 785 bool ok = true; 786 mozilla::MapTuple(*aArg, [&](auto& field) { 787 ok &= aConsumerView.ReadParam(&field); 788 return true; // ignored 789 }); 790 return ok; 791 } 792 }; 793 794 // - 795 796 template <class K, class V, class H, class E> 797 struct QueueParamTraits<std::unordered_map<K, V, H, E>> { 798 using ParamType = std::unordered_map<K, V, H, E>; 799 800 template <typename U> 801 static bool Write(ProducerView<U>& aProducerView, const ParamType& aArg) { 802 bool ok = aProducerView.WriteParam(uint64_t{aArg.size()}); 803 for (const auto& pair : aArg) { 804 ok &= aProducerView.WriteParam(pair); 805 } 806 return ok; 807 } 808 809 template <typename U> 810 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) { 811 aArg->clear(); 812 813 auto size = uint64_t{0}; 814 if (!aConsumerView.ReadParam(&size)) return false; 815 816 aArg->reserve(size); 817 for (const auto i : IntegerRange(size)) { 818 (void)i; 819 auto pair = std::pair<K, V>{}; 820 if (!aConsumerView.ReadParam(&pair)) return false; 821 aArg->insert(pair); 822 } 823 return true; 824 } 825 }; 826 827 } // namespace mozilla::webgl 828 829 #endif // _QUEUEPARAMTRAITS_H_