tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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_