Bug 1796811 - Update in-tree zlib to version 1.2.13. r=aosmond
[gecko.git] / ipc / glue / IPCMessageUtilsSpecializations.h
blob9cb462a83b5a92aaec5a0607fb146f4f7e305efc
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef __IPC_GLUE_IPCMESSAGEUTILSSPECIALIZATIONS_H__
8 #define __IPC_GLUE_IPCMESSAGEUTILSSPECIALIZATIONS_H__
10 #include <cstdint>
11 #include <cstdlib>
12 #include <limits>
13 #include <string>
14 #include <type_traits>
15 #include <unordered_map>
16 #include <utility>
17 #include <vector>
18 #include "chrome/common/ipc_message.h"
19 #include "chrome/common/ipc_message_utils.h"
20 #include "ipc/EnumSerializer.h"
21 #include "ipc/IPCMessageUtils.h"
22 #include "mozilla/Assertions.h"
23 #include "mozilla/BitSet.h"
24 #include "mozilla/EnumSet.h"
25 #include "mozilla/EnumTypeTraits.h"
26 #include "mozilla/IntegerRange.h"
27 #include "mozilla/Maybe.h"
28 #include "mozilla/TimeStamp.h"
29 #ifdef XP_WIN
30 # include "mozilla/TimeStamp_windows.h"
31 #endif
32 #include "mozilla/Tuple.h"
33 #include "mozilla/UniquePtr.h"
34 #include "mozilla/Unused.h"
35 #include "mozilla/Vector.h"
36 #include "mozilla/dom/ipc/StructuredCloneData.h"
37 #include "nsCSSPropertyID.h"
38 #include "nsDebug.h"
39 #include "nsIContentPolicy.h"
40 #include "nsID.h"
41 #include "nsILoadInfo.h"
42 #include "nsIThread.h"
43 #include "nsLiteralString.h"
44 #include "nsString.h"
45 #include "nsTArray.h"
46 #include "nsTHashSet.h"
48 // XXX Includes that are only required by implementations which could be moved
49 // to the cpp file.
50 #include "base/string_util.h" // for StringPrintf
51 #include "mozilla/ArrayUtils.h" // for ArrayLength
52 #include "mozilla/CheckedInt.h"
54 #ifdef _MSC_VER
55 # pragma warning(disable : 4800)
56 #endif
58 namespace mozilla {
59 template <typename... Ts>
60 class Variant;
62 namespace detail {
63 template <typename... Ts>
64 struct VariantTag;
66 } // namespace mozilla
68 namespace mozilla::dom {
69 template <typename T>
70 class Optional;
73 class nsAtom;
75 namespace IPC {
77 template <class T>
78 struct ParamTraits<nsTSubstring<T>> {
79 typedef nsTSubstring<T> paramType;
81 static void Write(MessageWriter* aWriter, const paramType& aParam) {
82 bool isVoid = aParam.IsVoid();
83 aWriter->WriteBool(isVoid);
85 if (isVoid) {
86 // represents a nullptr pointer
87 return;
90 WriteSequenceParam<const T&>(aWriter, aParam.BeginReading(),
91 aParam.Length());
94 static bool Read(MessageReader* aReader, paramType* aResult) {
95 bool isVoid;
96 if (!aReader->ReadBool(&isVoid)) {
97 return false;
100 if (isVoid) {
101 aResult->SetIsVoid(true);
102 return true;
105 return ReadSequenceParam(aReader, [&](uint32_t aLength) -> T* {
106 T* data = nullptr;
107 aResult->GetMutableData(&data, aLength);
108 return data;
113 template <class T>
114 struct ParamTraits<nsTString<T>> : ParamTraits<nsTSubstring<T>> {};
116 template <class T>
117 struct ParamTraits<nsTLiteralString<T>> : ParamTraits<nsTSubstring<T>> {};
119 template <class T, size_t N>
120 struct ParamTraits<nsTAutoStringN<T, N>> : ParamTraits<nsTSubstring<T>> {};
122 template <class T>
123 struct ParamTraits<nsTDependentString<T>> : ParamTraits<nsTSubstring<T>> {};
125 // XXX While this has no special dependencies, it's currently only used in
126 // GfxMessageUtils and could be moved there, or generalized to potentially work
127 // with any nsTHashSet.
128 template <>
129 struct ParamTraits<nsTHashSet<uint64_t>> {
130 typedef nsTHashSet<uint64_t> paramType;
132 static void Write(MessageWriter* aWriter, const paramType& aParam) {
133 uint32_t count = aParam.Count();
134 WriteParam(aWriter, count);
135 for (const auto& key : aParam) {
136 WriteParam(aWriter, key);
140 static bool Read(MessageReader* aReader, paramType* aResult) {
141 uint32_t count;
142 if (!ReadParam(aReader, &count)) {
143 return false;
145 paramType table(count);
146 for (uint32_t i = 0; i < count; ++i) {
147 uint64_t key;
148 if (!ReadParam(aReader, &key)) {
149 return false;
151 table.Insert(key);
153 *aResult = std::move(table);
154 return true;
158 template <typename E>
159 struct ParamTraits<nsTArray<E>> {
160 typedef nsTArray<E> paramType;
162 static void Write(MessageWriter* aWriter, const paramType& aParam) {
163 WriteSequenceParam<const E&>(aWriter, aParam.Elements(), aParam.Length());
166 static void Write(MessageWriter* aWriter, paramType&& aParam) {
167 WriteSequenceParam<E&&>(aWriter, aParam.Elements(), aParam.Length());
170 static bool Read(MessageReader* aReader, paramType* aResult) {
171 return ReadSequenceParam(aReader, [&](uint32_t aLength) -> E* {
172 return aResult->AppendElements(aLength);
177 template <typename E>
178 struct ParamTraits<CopyableTArray<E>> : ParamTraits<nsTArray<E>> {};
180 template <typename E>
181 struct ParamTraits<FallibleTArray<E>> {
182 typedef FallibleTArray<E> paramType;
184 static void Write(MessageWriter* aWriter, const paramType& aParam) {
185 WriteSequenceParam<const E&>(aWriter, aParam.Elements(), aParam.Length());
188 static void Write(MessageWriter* aWriter, paramType&& aParam) {
189 WriteSequenceParam<E&&>(aWriter, aParam.Elements(), aParam.Length());
192 static bool Read(MessageReader* aReader, paramType* aResult) {
193 return ReadSequenceParam(aReader, [&](uint32_t aLength) -> E* {
194 return aResult->AppendElements(aLength, mozilla::fallible);
199 template <typename E, size_t N>
200 struct ParamTraits<AutoTArray<E, N>> : ParamTraits<nsTArray<E>> {
201 typedef AutoTArray<E, N> paramType;
204 template <typename E, size_t N>
205 struct ParamTraits<CopyableAutoTArray<E, N>> : ParamTraits<AutoTArray<E, N>> {};
207 template <typename T>
208 struct ParamTraits<mozilla::dom::Sequence<T>> : ParamTraits<FallibleTArray<T>> {
211 template <typename E, size_t N, typename AP>
212 struct ParamTraits<mozilla::Vector<E, N, AP>> {
213 typedef mozilla::Vector<E, N, AP> paramType;
215 static void Write(MessageWriter* aWriter, const paramType& aParam) {
216 WriteSequenceParam<const E&>(aWriter, aParam.Elements(), aParam.Length());
219 static void Write(MessageWriter* aWriter, paramType&& aParam) {
220 WriteSequenceParam<E&&>(aWriter, aParam.Elements(), aParam.Length());
223 static bool Read(MessageReader* aReader, paramType* aResult) {
224 return ReadSequenceParam(aReader, [&](uint32_t aLength) -> E* {
225 if (!aResult->resize(aLength)) {
226 // So that OOM failure shows up as OOM crash instead of IPC FatalError.
227 NS_ABORT_OOM(aLength * sizeof(E));
229 return aResult->begin();
234 template <typename E>
235 struct ParamTraits<std::vector<E>> {
236 typedef std::vector<E> paramType;
238 static void Write(MessageWriter* aWriter, const paramType& aParam) {
239 WriteSequenceParam<const E&>(aWriter, aParam.data(), aParam.size());
241 static void Write(MessageWriter* aWriter, paramType&& aParam) {
242 WriteSequenceParam<E&&>(aWriter, aParam.data(), aParam.size());
245 static bool Read(MessageReader* aReader, paramType* aResult) {
246 return ReadSequenceParam(aReader, [&](uint32_t aLength) -> E* {
247 aResult->resize(aLength);
248 return aResult->data();
253 template <typename K, typename V>
254 struct ParamTraits<std::unordered_map<K, V>> final {
255 using T = std::unordered_map<K, V>;
257 static void Write(MessageWriter* const writer, const T& in) {
258 WriteParam(writer, in.size());
259 for (const auto& pair : in) {
260 WriteParam(writer, pair.first);
261 WriteParam(writer, pair.second);
265 static bool Read(MessageReader* const reader, T* const out) {
266 size_t size = 0;
267 if (!ReadParam(reader, &size)) return false;
268 T map;
269 map.reserve(size);
270 for (const auto i : mozilla::IntegerRange(size)) {
271 std::pair<K, V> pair;
272 mozilla::Unused << i;
273 if (!ReadParam(reader, &(pair.first)) ||
274 !ReadParam(reader, &(pair.second))) {
275 return false;
277 map.insert(std::move(pair));
279 *out = std::move(map);
280 return true;
284 template <>
285 struct ParamTraits<float> {
286 typedef float paramType;
288 static void Write(MessageWriter* aWriter, const paramType& aParam) {
289 aWriter->WriteBytes(&aParam, sizeof(paramType));
292 static bool Read(MessageReader* aReader, paramType* aResult) {
293 return aReader->ReadBytesInto(aResult, sizeof(*aResult));
297 template <>
298 struct ParamTraits<nsCSSPropertyID>
299 : public ContiguousEnumSerializer<nsCSSPropertyID, eCSSProperty_UNKNOWN,
300 eCSSProperty_COUNT> {};
302 template <>
303 struct ParamTraits<nsID> {
304 typedef nsID paramType;
306 static void Write(MessageWriter* aWriter, const paramType& aParam) {
307 WriteParam(aWriter, aParam.m0);
308 WriteParam(aWriter, aParam.m1);
309 WriteParam(aWriter, aParam.m2);
310 for (unsigned int i = 0; i < mozilla::ArrayLength(aParam.m3); i++) {
311 WriteParam(aWriter, aParam.m3[i]);
315 static bool Read(MessageReader* aReader, paramType* aResult) {
316 if (!ReadParam(aReader, &(aResult->m0)) ||
317 !ReadParam(aReader, &(aResult->m1)) ||
318 !ReadParam(aReader, &(aResult->m2)))
319 return false;
321 for (unsigned int i = 0; i < mozilla::ArrayLength(aResult->m3); i++)
322 if (!ReadParam(aReader, &(aResult->m3[i]))) return false;
324 return true;
328 template <>
329 struct ParamTraits<nsContentPolicyType>
330 : public ContiguousEnumSerializerInclusive<
331 nsContentPolicyType, nsIContentPolicy::TYPE_INVALID,
332 nsIContentPolicy::TYPE_WEB_IDENTITY> {};
334 template <>
335 struct ParamTraits<mozilla::TimeDuration> {
336 typedef mozilla::TimeDuration paramType;
337 static void Write(MessageWriter* aWriter, const paramType& aParam) {
338 WriteParam(aWriter, aParam.mValue);
340 static bool Read(MessageReader* aReader, paramType* aResult) {
341 return ReadParam(aReader, &aResult->mValue);
345 template <>
346 struct ParamTraits<mozilla::TimeStamp> {
347 typedef mozilla::TimeStamp paramType;
348 static void Write(MessageWriter* aWriter, const paramType& aParam) {
349 WriteParam(aWriter, aParam.mValue);
351 static bool Read(MessageReader* aReader, paramType* aResult) {
352 return ReadParam(aReader, &aResult->mValue);
356 #ifdef XP_WIN
358 template <>
359 struct ParamTraits<mozilla::TimeStampValue> {
360 typedef mozilla::TimeStampValue paramType;
361 static void Write(MessageWriter* aWriter, const paramType& aParam) {
362 WriteParam(aWriter, aParam.mGTC);
363 WriteParam(aWriter, aParam.mQPC);
364 WriteParam(aWriter, aParam.mIsNull);
365 WriteParam(aWriter, aParam.mHasQPC);
367 static bool Read(MessageReader* aReader, paramType* aResult) {
368 return (ReadParam(aReader, &aResult->mGTC) &&
369 ReadParam(aReader, &aResult->mQPC) &&
370 ReadParam(aReader, &aResult->mIsNull) &&
371 ReadParam(aReader, &aResult->mHasQPC));
375 #endif
377 template <>
378 struct ParamTraits<mozilla::dom::ipc::StructuredCloneData> {
379 typedef mozilla::dom::ipc::StructuredCloneData paramType;
381 static void Write(MessageWriter* aWriter, const paramType& aParam) {
382 aParam.WriteIPCParams(aWriter);
385 static bool Read(MessageReader* aReader, paramType* aResult) {
386 return aResult->ReadIPCParams(aReader);
390 template <class T>
391 struct ParamTraits<mozilla::Maybe<T>> {
392 typedef mozilla::Maybe<T> paramType;
394 static void Write(MessageWriter* writer, const paramType& param) {
395 if (param.isSome()) {
396 WriteParam(writer, true);
397 WriteParam(writer, param.ref());
398 } else {
399 WriteParam(writer, false);
403 static void Write(MessageWriter* writer, paramType&& param) {
404 if (param.isSome()) {
405 WriteParam(writer, true);
406 WriteParam(writer, std::move(param.ref()));
407 } else {
408 WriteParam(writer, false);
412 static bool Read(MessageReader* reader, paramType* result) {
413 bool isSome;
414 if (!ReadParam(reader, &isSome)) {
415 return false;
417 if (isSome) {
418 T tmp;
419 if (!ReadParam(reader, &tmp)) {
420 return false;
422 *result = mozilla::Some(std::move(tmp));
423 } else {
424 *result = mozilla::Nothing();
426 return true;
430 template <typename T, typename U>
431 struct ParamTraits<mozilla::EnumSet<T, U>> {
432 typedef mozilla::EnumSet<T, U> paramType;
433 typedef U serializedType;
435 static void Write(MessageWriter* writer, const paramType& param) {
436 MOZ_RELEASE_ASSERT(IsLegalValue(param.serialize()));
437 WriteParam(writer, param.serialize());
440 static bool Read(MessageReader* reader, paramType* result) {
441 serializedType tmp;
443 if (ReadParam(reader, &tmp)) {
444 if (IsLegalValue(tmp)) {
445 result->deserialize(tmp);
446 return true;
450 return false;
453 static constexpr serializedType AllEnumBits() {
454 return ~serializedType(0) >> (std::numeric_limits<serializedType>::digits -
455 (mozilla::MaxEnumValue<T>::value + 1));
458 static constexpr bool IsLegalValue(const serializedType value) {
459 static_assert(mozilla::MaxEnumValue<T>::value <
460 std::numeric_limits<serializedType>::digits,
461 "Enum max value is not in the range!");
462 static_assert(
463 std::is_unsigned<decltype(mozilla::MaxEnumValue<T>::value)>::value,
464 "Type of MaxEnumValue<T>::value specialization should be unsigned!");
466 return (value & AllEnumBits()) == value;
470 template <class... Ts>
471 struct ParamTraits<mozilla::Variant<Ts...>> {
472 typedef mozilla::Variant<Ts...> paramType;
473 using Tag = typename mozilla::detail::VariantTag<Ts...>::Type;
475 static void Write(MessageWriter* writer, const paramType& param) {
476 WriteParam(writer, param.tag);
477 param.match([writer](const auto& t) { WriteParam(writer, t); });
480 // Because VariantReader is a nested struct, we need the dummy template
481 // parameter to avoid making VariantReader<0> an explicit specialization,
482 // which is not allowed for a nested class template
483 template <size_t N, typename dummy = void>
484 struct VariantReader {
485 using Next = VariantReader<N - 1>;
487 static bool Read(MessageReader* reader, Tag tag, paramType* result) {
488 // Since the VariantReader specializations start at N , we need to
489 // subtract one to look at N - 1, the first valid tag. This means our
490 // comparisons are off by 1. If we get to N = 0 then we have failed to
491 // find a match to the tag.
492 if (tag == N - 1) {
493 // Recall, even though the template parameter is N, we are
494 // actually interested in the N - 1 tag.
495 // Default construct our field within the result outparameter and
496 // directly deserialize into the variant. Note that this means that
497 // every type in Ts needs to be default constructible
498 return ReadParam(reader, &result->template emplace<N - 1>());
499 } else {
500 return Next::Read(reader, tag, result);
504 }; // VariantReader<N>
506 // Since we are conditioning on tag = N - 1 in the preceding specialization,
507 // if we get to `VariantReader<0, dummy>` we have failed to find
508 // a matching tag.
509 template <typename dummy>
510 struct VariantReader<0, dummy> {
511 static bool Read(MessageReader* reader, Tag tag, paramType* result) {
512 return false;
516 static bool Read(MessageReader* reader, paramType* result) {
517 Tag tag;
518 if (ReadParam(reader, &tag)) {
519 return VariantReader<sizeof...(Ts)>::Read(reader, tag, result);
521 return false;
525 template <typename T>
526 struct ParamTraits<mozilla::dom::Optional<T>> {
527 typedef mozilla::dom::Optional<T> paramType;
529 static void Write(MessageWriter* aWriter, const paramType& aParam) {
530 if (aParam.WasPassed()) {
531 WriteParam(aWriter, true);
532 WriteParam(aWriter, aParam.Value());
533 return;
536 WriteParam(aWriter, false);
539 static bool Read(MessageReader* aReader, paramType* aResult) {
540 bool wasPassed = false;
542 if (!ReadParam(aReader, &wasPassed)) {
543 return false;
546 aResult->Reset();
548 if (wasPassed) {
549 if (!ReadParam(aReader, &aResult->Construct())) {
550 return false;
554 return true;
558 template <>
559 struct ParamTraits<nsAtom*> {
560 typedef nsAtom paramType;
562 static void Write(MessageWriter* aWriter, const paramType* aParam);
563 static bool Read(MessageReader* aReader, RefPtr<paramType>* aResult);
566 struct CrossOriginOpenerPolicyValidator {
567 using IntegralType =
568 std::underlying_type_t<nsILoadInfo::CrossOriginOpenerPolicy>;
570 static bool IsLegalValue(const IntegralType e) {
571 return AreIntegralValuesEqual(e, nsILoadInfo::OPENER_POLICY_UNSAFE_NONE) ||
572 AreIntegralValuesEqual(e, nsILoadInfo::OPENER_POLICY_SAME_ORIGIN) ||
573 AreIntegralValuesEqual(
574 e, nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_ALLOW_POPUPS) ||
575 AreIntegralValuesEqual(
576 e, nsILoadInfo::
577 OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP);
580 private:
581 static bool AreIntegralValuesEqual(
582 const IntegralType aLhs,
583 const nsILoadInfo::CrossOriginOpenerPolicy aRhs) {
584 return aLhs == static_cast<IntegralType>(aRhs);
588 template <>
589 struct ParamTraits<nsILoadInfo::CrossOriginOpenerPolicy>
590 : EnumSerializer<nsILoadInfo::CrossOriginOpenerPolicy,
591 CrossOriginOpenerPolicyValidator> {};
593 struct CrossOriginEmbedderPolicyValidator {
594 using IntegralType =
595 std::underlying_type_t<nsILoadInfo::CrossOriginEmbedderPolicy>;
597 static bool IsLegalValue(const IntegralType e) {
598 return AreIntegralValuesEqual(e, nsILoadInfo::EMBEDDER_POLICY_NULL) ||
599 AreIntegralValuesEqual(e,
600 nsILoadInfo::EMBEDDER_POLICY_REQUIRE_CORP) ||
601 AreIntegralValuesEqual(e,
602 nsILoadInfo::EMBEDDER_POLICY_CREDENTIALLESS);
605 private:
606 static bool AreIntegralValuesEqual(
607 const IntegralType aLhs,
608 const nsILoadInfo::CrossOriginEmbedderPolicy aRhs) {
609 return aLhs == static_cast<IntegralType>(aRhs);
613 template <>
614 struct ParamTraits<nsILoadInfo::CrossOriginEmbedderPolicy>
615 : EnumSerializer<nsILoadInfo::CrossOriginEmbedderPolicy,
616 CrossOriginEmbedderPolicyValidator> {};
618 template <size_t N, typename Word>
619 struct ParamTraits<mozilla::BitSet<N, Word>> {
620 typedef mozilla::BitSet<N, Word> paramType;
622 static void Write(MessageWriter* aWriter, const paramType& aParam) {
623 for (Word word : aParam.Storage()) {
624 WriteParam(aWriter, word);
628 static bool Read(MessageReader* aReader, paramType* aResult) {
629 for (Word& word : aResult->Storage()) {
630 if (!ReadParam(aReader, &word)) {
631 return false;
634 return true;
638 template <typename T>
639 struct ParamTraits<mozilla::UniquePtr<T>> {
640 typedef mozilla::UniquePtr<T> paramType;
642 static void Write(MessageWriter* aWriter, const paramType& aParam) {
643 bool isNull = aParam == nullptr;
644 WriteParam(aWriter, isNull);
646 if (!isNull) {
647 WriteParam(aWriter, *aParam.get());
651 static bool Read(IPC::MessageReader* aReader, paramType* aResult) {
652 bool isNull = true;
653 if (!ReadParam(aReader, &isNull)) {
654 return false;
657 if (isNull) {
658 aResult->reset();
659 } else {
660 *aResult = mozilla::MakeUnique<T>();
661 if (!ReadParam(aReader, aResult->get())) {
662 return false;
665 return true;
669 template <typename... Ts>
670 struct ParamTraits<mozilla::Tuple<Ts...>> {
671 typedef mozilla::Tuple<Ts...> paramType;
673 template <typename U>
674 static void Write(IPC::MessageWriter* aWriter, U&& aParam) {
675 WriteInternal(aWriter, std::forward<U>(aParam),
676 std::index_sequence_for<Ts...>{});
679 static bool Read(IPC::MessageReader* aReader,
680 mozilla::Tuple<Ts...>* aResult) {
681 return ReadInternal(aReader, *aResult, std::index_sequence_for<Ts...>{});
684 private:
685 template <size_t... Is>
686 static void WriteInternal(IPC::MessageWriter* aWriter,
687 const mozilla::Tuple<Ts...>& aParam,
688 std::index_sequence<Is...>) {
689 WriteParams(aWriter, mozilla::Get<Is>(aParam)...);
692 template <size_t... Is>
693 static void WriteInternal(IPC::MessageWriter* aWriter,
694 mozilla::Tuple<Ts...>&& aParam,
695 std::index_sequence<Is...>) {
696 WriteParams(aWriter, std::move(mozilla::Get<Is>(aParam))...);
699 template <size_t... Is>
700 static bool ReadInternal(IPC::MessageReader* aReader,
701 mozilla::Tuple<Ts...>& aResult,
702 std::index_sequence<Is...>) {
703 return ReadParams(aReader, mozilla::Get<Is>(aResult)...);
707 } /* namespace IPC */
709 #endif /* __IPC_GLUE_IPCMESSAGEUTILSSPECIALIZATIONS_H__ */