diff options
Diffstat (limited to 'ipc/glue/IPCMessageUtilsSpecializations.h')
-rw-r--r-- | ipc/glue/IPCMessageUtilsSpecializations.h | 938 |
1 files changed, 938 insertions, 0 deletions
diff --git a/ipc/glue/IPCMessageUtilsSpecializations.h b/ipc/glue/IPCMessageUtilsSpecializations.h new file mode 100644 index 0000000000..4fcaac046c --- /dev/null +++ b/ipc/glue/IPCMessageUtilsSpecializations.h @@ -0,0 +1,938 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __IPC_GLUE_IPCMESSAGEUTILSSPECIALIZATIONS_H__ +#define __IPC_GLUE_IPCMESSAGEUTILSSPECIALIZATIONS_H__ + +#include <cstdint> +#include <cstdlib> +#include <limits> +#include <string> +#include <type_traits> +#include <unordered_map> +#include <utility> +#include <vector> +#include "chrome/common/ipc_message.h" +#include "chrome/common/ipc_message_utils.h" +#include "ipc/EnumSerializer.h" +#include "ipc/IPCMessageUtils.h" +#include "mozilla/Assertions.h" +#include "mozilla/BitSet.h" +#include "mozilla/EnumSet.h" +#include "mozilla/EnumTypeTraits.h" +#include "mozilla/IntegerRange.h" +#include "mozilla/Maybe.h" +#include "mozilla/TimeStamp.h" +#ifdef XP_WIN +# include "mozilla/TimeStamp_windows.h" +#endif +#include "mozilla/Unused.h" +#include "mozilla/Vector.h" +#include "mozilla/dom/ipc/StructuredCloneData.h" +#include "nsCSSPropertyID.h" +#include "nsDebug.h" +#include "nsHashKeys.h" +#include "nsIContentPolicy.h" +#include "nsID.h" +#include "nsILoadInfo.h" +#include "nsIThread.h" +#include "nsLiteralString.h" +#include "nsString.h" +#include "nsTArray.h" +#include "nsTHashtable.h" + +// XXX Includes that are only required by implementations which could be moved +// to the cpp file. +#include "base/string_util.h" // for StringPrintf +#include "mozilla/ArrayUtils.h" // for ArrayLength +#include "mozilla/CheckedInt.h" + +#ifdef _MSC_VER +# pragma warning(disable : 4800) +#endif + +namespace mozilla { +template <typename... Ts> +class Variant; + +namespace detail { +template <typename... Ts> +struct VariantTag; +} +} // namespace mozilla + +namespace mozilla::dom { +template <typename T> +class Optional; +} + +namespace IPC { + +template <> +struct ParamTraits<nsACString> { + typedef nsACString paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + bool isVoid = aParam.IsVoid(); + aMsg->WriteBool(isVoid); + + if (isVoid) + // represents a nullptr pointer + return; + + uint32_t length = aParam.Length(); + WriteParam(aMsg, length); + aMsg->WriteBytes(aParam.BeginReading(), length); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + bool isVoid; + if (!aMsg->ReadBool(aIter, &isVoid)) return false; + + if (isVoid) { + aResult->SetIsVoid(true); + return true; + } + + uint32_t length; + if (!ReadParam(aMsg, aIter, &length)) { + return false; + } + if (!aMsg->HasBytesAvailable(aIter, length)) { + return false; + } + aResult->SetLength(length); + + return aMsg->ReadBytesInto(aIter, aResult->BeginWriting(), length); + } + + static void Log(const paramType& aParam, std::wstring* aLog) { + if (aParam.IsVoid()) + aLog->append(L"(NULL)"); + else + aLog->append(UTF8ToWide(aParam.BeginReading())); + } +}; + +template <> +struct ParamTraits<nsAString> { + typedef nsAString paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + bool isVoid = aParam.IsVoid(); + aMsg->WriteBool(isVoid); + + if (isVoid) + // represents a nullptr pointer + return; + + uint32_t length = aParam.Length(); + WriteParam(aMsg, length); + aMsg->WriteBytes(aParam.BeginReading(), length * sizeof(char16_t)); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + bool isVoid; + if (!aMsg->ReadBool(aIter, &isVoid)) return false; + + if (isVoid) { + aResult->SetIsVoid(true); + return true; + } + + uint32_t length; + if (!ReadParam(aMsg, aIter, &length)) { + return false; + } + + mozilla::CheckedInt<uint32_t> byteLength = + mozilla::CheckedInt<uint32_t>(length) * sizeof(char16_t); + if (!byteLength.isValid() || + !aMsg->HasBytesAvailable(aIter, byteLength.value())) { + return false; + } + + aResult->SetLength(length); + + return aMsg->ReadBytesInto(aIter, aResult->BeginWriting(), + byteLength.value()); + } + + static void Log(const paramType& aParam, std::wstring* aLog) { + if (aParam.IsVoid()) + aLog->append(L"(NULL)"); + else { +#ifdef WCHAR_T_IS_UTF16 + aLog->append(reinterpret_cast<const wchar_t*>(aParam.BeginReading())); +#else + uint32_t length = aParam.Length(); + for (uint32_t index = 0; index < length; index++) { + aLog->push_back(std::wstring::value_type(aParam[index])); + } +#endif + } + } +}; + +template <> +struct ParamTraits<nsCString> : ParamTraits<nsACString> { + typedef nsCString paramType; +}; + +template <> +struct ParamTraits<nsLiteralCString> : ParamTraits<nsACString> { + typedef nsLiteralCString paramType; +}; + +#ifdef MOZILLA_INTERNAL_API + +template <> +struct ParamTraits<nsAutoCString> : ParamTraits<nsCString> { + typedef nsAutoCString paramType; +}; + +#endif // MOZILLA_INTERNAL_API + +template <> +struct ParamTraits<nsString> : ParamTraits<nsAString> { + typedef nsString paramType; +}; + +template <> +struct ParamTraits<nsLiteralString> : ParamTraits<nsAString> { + typedef nsLiteralString paramType; +}; + +template <> +struct ParamTraits<nsDependentSubstring> : ParamTraits<nsAString> { + typedef nsDependentSubstring paramType; +}; + +template <> +struct ParamTraits<nsDependentCSubstring> : ParamTraits<nsACString> { + typedef nsDependentCSubstring paramType; +}; + +#ifdef MOZILLA_INTERNAL_API + +template <> +struct ParamTraits<nsAutoString> : ParamTraits<nsString> { + typedef nsAutoString paramType; +}; + +#endif // MOZILLA_INTERNAL_API + +template <> +struct ParamTraits<nsTHashtable<nsUint64HashKey>> { + typedef nsTHashtable<nsUint64HashKey> paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + uint32_t count = aParam.Count(); + WriteParam(aMsg, count); + for (auto iter = aParam.ConstIter(); !iter.Done(); iter.Next()) { + WriteParam(aMsg, iter.Get()->GetKey()); + } + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + uint32_t count; + if (!ReadParam(aMsg, aIter, &count)) { + return false; + } + paramType table(count); + for (uint32_t i = 0; i < count; ++i) { + uint64_t key; + if (!ReadParam(aMsg, aIter, &key)) { + return false; + } + table.PutEntry(key); + } + *aResult = std::move(table); + return true; + } +}; + +// Pickle::ReadBytes and ::WriteBytes take the length in ints, so we must +// ensure there is no overflow. This returns |false| if it would overflow. +// Otherwise, it returns |true| and places the byte length in |aByteLength|. +bool ByteLengthIsValid(uint32_t aNumElements, size_t aElementSize, + int* aByteLength); + +// Note: IPDL will sometimes codegen specialized implementations of +// nsTArray serialization and deserialization code in +// implementSpecialArrayPickling(). This is needed when ParamTraits<E> +// is not defined. +template <typename E> +struct ParamTraits<nsTArray<E>> { + typedef nsTArray<E> paramType; + + // We write arrays of integer or floating-point data using a single pickling + // call, rather than writing each element individually. We deliberately do + // not use mozilla::IsPod here because it is perfectly reasonable to have + // a data structure T for which IsPod<T>::value is true, yet also have a + // ParamTraits<T> specialization. + static const bool sUseWriteBytes = + (std::is_integral_v<E> || std::is_floating_point_v<E>); + + static void Write(Message* aMsg, const paramType& aParam) { + uint32_t length = aParam.Length(); + WriteParam(aMsg, length); + + if (sUseWriteBytes) { + int pickledLength = 0; + MOZ_RELEASE_ASSERT(ByteLengthIsValid(length, sizeof(E), &pickledLength)); + aMsg->WriteBytes(aParam.Elements(), pickledLength); + } else { + const E* elems = aParam.Elements(); + for (uint32_t index = 0; index < length; index++) { + WriteParam(aMsg, elems[index]); + } + } + } + + // This method uses infallible allocation so that an OOM failure will + // show up as an OOM crash rather than an IPC FatalError. + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + uint32_t length; + if (!ReadParam(aMsg, aIter, &length)) { + return false; + } + + if (sUseWriteBytes) { + int pickledLength = 0; + if (!ByteLengthIsValid(length, sizeof(E), &pickledLength)) { + return false; + } + + E* elements = aResult->AppendElements(length); + return aMsg->ReadBytesInto(aIter, elements, pickledLength); + } else { + // Each ReadParam<E> may read more than 1 byte each; this is an attempt + // to minimally validate that the length isn't much larger than what's + // actually available in aMsg. + if (!aMsg->HasBytesAvailable(aIter, length)) { + return false; + } + + aResult->SetCapacity(length); + + for (uint32_t index = 0; index < length; index++) { + E* element = aResult->AppendElement(); + if (!ReadParam(aMsg, aIter, element)) { + return false; + } + } + return true; + } + } + + static void Log(const paramType& aParam, std::wstring* aLog) { + for (uint32_t index = 0; index < aParam.Length(); index++) { + if (index) { + aLog->append(L" "); + } + LogParam(aParam[index], aLog); + } + } +}; + +template <typename E> +struct ParamTraits<CopyableTArray<E>> : ParamTraits<nsTArray<E>> {}; + +template <typename E> +struct ParamTraits<FallibleTArray<E>> { + typedef FallibleTArray<E> paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + WriteParam(aMsg, static_cast<const nsTArray<E>&>(aParam)); + } + + // Deserialize the array infallibly, but return a FallibleTArray. + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + nsTArray<E> temp; + if (!ReadParam(aMsg, aIter, &temp)) return false; + + *aResult = std::move(temp); + return true; + } + + static void Log(const paramType& aParam, std::wstring* aLog) { + LogParam(static_cast<const nsTArray<E>&>(aParam), aLog); + } +}; + +template <typename E, size_t N> +struct ParamTraits<AutoTArray<E, N>> : ParamTraits<nsTArray<E>> { + typedef AutoTArray<E, N> paramType; +}; + +template <typename E, size_t N> +struct ParamTraits<CopyableAutoTArray<E, N>> : ParamTraits<AutoTArray<E, N>> {}; + +template <typename E, size_t N, typename AP> +struct ParamTraits<mozilla::Vector<E, N, AP>> { + typedef mozilla::Vector<E, N, AP> paramType; + + // We write arrays of integer or floating-point data using a single pickling + // call, rather than writing each element individually. We deliberately do + // not use mozilla::IsPod here because it is perfectly reasonable to have + // a data structure T for which IsPod<T>::value is true, yet also have a + // ParamTraits<T> specialization. + static const bool sUseWriteBytes = + (std::is_integral_v<E> || std::is_floating_point_v<E>); + + static void Write(Message* aMsg, const paramType& aParam) { + uint32_t length = aParam.length(); + WriteParam(aMsg, length); + + if (sUseWriteBytes) { + int pickledLength = 0; + MOZ_RELEASE_ASSERT(ByteLengthIsValid(length, sizeof(E), &pickledLength)); + aMsg->WriteBytes(aParam.begin(), pickledLength); + return; + } + + for (const E& elem : aParam) { + WriteParam(aMsg, elem); + } + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + uint32_t length; + if (!ReadParam(aMsg, aIter, &length)) { + return false; + } + + if (sUseWriteBytes) { + int pickledLength = 0; + if (!ByteLengthIsValid(length, sizeof(E), &pickledLength)) { + return false; + } + + if (!aResult->resizeUninitialized(length)) { + // So that OOM failure shows up as OOM crash instead of IPC FatalError. + NS_ABORT_OOM(length * sizeof(E)); + } + + E* elements = aResult->begin(); + return aMsg->ReadBytesInto(aIter, elements, pickledLength); + } + + // Each ReadParam<E> may read more than 1 byte each; this is an attempt + // to minimally validate that the length isn't much larger than what's + // actually available in aMsg. + if (!aMsg->HasBytesAvailable(aIter, length)) { + return false; + } + + if (!aResult->resize(length)) { + // So that OOM failure shows up as OOM crash instead of IPC FatalError. + NS_ABORT_OOM(length * sizeof(E)); + } + + for (uint32_t index = 0; index < length; ++index) { + if (!ReadParam(aMsg, aIter, &((*aResult)[index]))) { + return false; + } + } + + return true; + } + + static void Log(const paramType& aParam, std::wstring* aLog) { + for (uint32_t index = 0, len = aParam.length(); index < len; ++index) { + if (index) { + aLog->append(L" "); + } + LogParam(aParam[index], aLog); + } + } +}; + +template <typename E> +struct ParamTraits<std::vector<E>> { + typedef std::vector<E> paramType; + + // We write arrays of integer or floating-point data using a single pickling + // call, rather than writing each element individually. We deliberately do + // not use mozilla::IsPod here because it is perfectly reasonable to have + // a data structure T for which IsPod<T>::value is true, yet also have a + // ParamTraits<T> specialization. + static const bool sUseWriteBytes = + (std::is_integral_v<E> || std::is_floating_point_v<E>); + + static void Write(Message* aMsg, const paramType& aParam) { + uint32_t length = aParam.size(); + WriteParam(aMsg, length); + + if (sUseWriteBytes) { + int pickledLength = 0; + MOZ_RELEASE_ASSERT(ByteLengthIsValid(length, sizeof(E), &pickledLength)); + aMsg->WriteBytes(aParam.data(), pickledLength); + return; + } + + for (const E& elem : aParam) { + WriteParam(aMsg, elem); + } + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + uint32_t length; + if (!ReadParam(aMsg, aIter, &length)) { + return false; + } + + if (sUseWriteBytes) { + int pickledLength = 0; + if (!ByteLengthIsValid(length, sizeof(E), &pickledLength)) { + return false; + } + + aResult->resize(length); + + E* elements = aResult->data(); + return aMsg->ReadBytesInto(aIter, elements, pickledLength); + } + + // Each ReadParam<E> may read more than 1 byte each; this is an attempt + // to minimally validate that the length isn't much larger than what's + // actually available in aMsg. + if (!aMsg->HasBytesAvailable(aIter, length)) { + return false; + } + + aResult->resize(length); + + for (uint32_t index = 0; index < length; ++index) { + if (!ReadParam(aMsg, aIter, &((*aResult)[index]))) { + return false; + } + } + + return true; + } + + static void Log(const paramType& aParam, std::wstring* aLog) { + for (uint32_t index = 0, len = aParam.size(); index < len; ++index) { + if (index) { + aLog->append(L" "); + } + LogParam(aParam[index], aLog); + } + } +}; + +template <typename K, typename V> +struct ParamTraits<std::unordered_map<K, V>> final { + using T = std::unordered_map<K, V>; + + static void Write(Message* const msg, const T& in) { + WriteParam(msg, in.size()); + for (const auto& pair : in) { + WriteParam(msg, pair.first); + WriteParam(msg, pair.second); + } + } + + static bool Read(const Message* const msg, PickleIterator* const itr, + T* const out) { + size_t size = 0; + if (!ReadParam(msg, itr, &size)) return false; + T map; + map.reserve(size); + for (const auto i : mozilla::IntegerRange(size)) { + std::pair<K, V> pair; + mozilla::Unused << i; + if (!ReadParam(msg, itr, &(pair.first)) || + !ReadParam(msg, itr, &(pair.second))) { + return false; + } + map.insert(std::move(pair)); + } + *out = std::move(map); + return true; + } +}; + +template <> +struct ParamTraits<float> { + typedef float paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + aMsg->WriteBytes(&aParam, sizeof(paramType)); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + return aMsg->ReadBytesInto(aIter, aResult, sizeof(*aResult)); + } + + static void Log(const paramType& aParam, std::wstring* aLog) { + aLog->append(StringPrintf(L"%g", aParam)); + } +}; + +template <> +struct ParamTraits<nsCSSPropertyID> + : public ContiguousEnumSerializer<nsCSSPropertyID, eCSSProperty_UNKNOWN, + eCSSProperty_COUNT> {}; + +template <> +struct ParamTraits<nsID> { + typedef nsID paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + WriteParam(aMsg, aParam.m0); + WriteParam(aMsg, aParam.m1); + WriteParam(aMsg, aParam.m2); + for (unsigned int i = 0; i < mozilla::ArrayLength(aParam.m3); i++) { + WriteParam(aMsg, aParam.m3[i]); + } + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + if (!ReadParam(aMsg, aIter, &(aResult->m0)) || + !ReadParam(aMsg, aIter, &(aResult->m1)) || + !ReadParam(aMsg, aIter, &(aResult->m2))) + return false; + + for (unsigned int i = 0; i < mozilla::ArrayLength(aResult->m3); i++) + if (!ReadParam(aMsg, aIter, &(aResult->m3[i]))) return false; + + return true; + } + + static void Log(const paramType& aParam, std::wstring* aLog) { + aLog->append(L"{"); + aLog->append( + StringPrintf(L"%8.8X-%4.4X-%4.4X-", aParam.m0, aParam.m1, aParam.m2)); + for (unsigned int i = 0; i < mozilla::ArrayLength(aParam.m3); i++) + aLog->append(StringPrintf(L"%2.2X", aParam.m3[i])); + aLog->append(L"}"); + } +}; + +template <> +struct ParamTraits<nsContentPolicyType> + : public ContiguousEnumSerializerInclusive< + nsContentPolicyType, nsIContentPolicy::TYPE_INVALID, + nsIContentPolicy::TYPE_INTERNAL_FETCH_PRELOAD> {}; + +template <> +struct ParamTraits<mozilla::TimeDuration> { + typedef mozilla::TimeDuration paramType; + static void Write(Message* aMsg, const paramType& aParam) { + WriteParam(aMsg, aParam.mValue); + } + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + return ReadParam(aMsg, aIter, &aResult->mValue); + }; +}; + +template <> +struct ParamTraits<mozilla::TimeStamp> { + typedef mozilla::TimeStamp paramType; + static void Write(Message* aMsg, const paramType& aParam) { + WriteParam(aMsg, aParam.mValue); + } + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + return ReadParam(aMsg, aIter, &aResult->mValue); + }; +}; + +#ifdef XP_WIN + +template <> +struct ParamTraits<mozilla::TimeStampValue> { + typedef mozilla::TimeStampValue paramType; + static void Write(Message* aMsg, const paramType& aParam) { + WriteParam(aMsg, aParam.mGTC); + WriteParam(aMsg, aParam.mQPC); + WriteParam(aMsg, aParam.mUsedCanonicalNow); + WriteParam(aMsg, aParam.mIsNull); + WriteParam(aMsg, aParam.mHasQPC); + } + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + return (ReadParam(aMsg, aIter, &aResult->mGTC) && + ReadParam(aMsg, aIter, &aResult->mQPC) && + ReadParam(aMsg, aIter, &aResult->mUsedCanonicalNow) && + ReadParam(aMsg, aIter, &aResult->mIsNull) && + ReadParam(aMsg, aIter, &aResult->mHasQPC)); + } +}; + +#else + +template <> +struct ParamTraits<mozilla::TimeStamp63Bit> { + typedef mozilla::TimeStamp63Bit paramType; + static void Write(Message* aMsg, const paramType& aParam) { + WriteParam(aMsg, aParam.mUsedCanonicalNow); + WriteParam(aMsg, aParam.mTimeStamp); + } + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + bool success = true; + uint64_t result; + + success &= ReadParam(aMsg, aIter, &result); + aResult->mUsedCanonicalNow = result & 0x01; + + success &= ReadParam(aMsg, aIter, &result); + aResult->mTimeStamp = result & 0x7FFFFFFFFFFFFFFF; + + return success; + } +}; + +#endif + +template <> +struct ParamTraits<mozilla::dom::ipc::StructuredCloneData> { + typedef mozilla::dom::ipc::StructuredCloneData paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + aParam.WriteIPCParams(aMsg); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + return aResult->ReadIPCParams(aMsg, aIter); + } + + static void Log(const paramType& aParam, std::wstring* aLog) { + LogParam(aParam.DataLength(), aLog); + } +}; + +template <class T> +struct ParamTraits<mozilla::Maybe<T>> { + typedef mozilla::Maybe<T> paramType; + + static void Write(Message* msg, const paramType& param) { + if (param.isSome()) { + WriteParam(msg, true); + WriteParam(msg, param.value()); + } else { + WriteParam(msg, false); + } + } + + static bool Read(const Message* msg, PickleIterator* iter, + paramType* result) { + bool isSome; + if (!ReadParam(msg, iter, &isSome)) { + return false; + } + if (isSome) { + T tmp; + if (!ReadParam(msg, iter, &tmp)) { + return false; + } + *result = mozilla::Some(std::move(tmp)); + } else { + *result = mozilla::Nothing(); + } + return true; + } +}; + +template <typename T, typename U> +struct ParamTraits<mozilla::EnumSet<T, U>> { + typedef mozilla::EnumSet<T, U> paramType; + typedef U serializedType; + + static void Write(Message* msg, const paramType& param) { + MOZ_RELEASE_ASSERT(IsLegalValue(param.serialize())); + WriteParam(msg, param.serialize()); + } + + static bool Read(const Message* msg, PickleIterator* iter, + paramType* result) { + serializedType tmp; + + if (ReadParam(msg, iter, &tmp)) { + if (IsLegalValue(tmp)) { + result->deserialize(tmp); + return true; + } + } + + return false; + } + + static constexpr serializedType AllEnumBits() { + return ~serializedType(0) >> (std::numeric_limits<serializedType>::digits - + (mozilla::MaxEnumValue<T>::value + 1)); + } + + static constexpr bool IsLegalValue(const serializedType value) { + static_assert(mozilla::MaxEnumValue<T>::value < + std::numeric_limits<serializedType>::digits, + "Enum max value is not in the range!"); + static_assert( + std::is_unsigned<decltype(mozilla::MaxEnumValue<T>::value)>::value, + "Type of MaxEnumValue<T>::value specialization should be unsigned!"); + + return (value & AllEnumBits()) == value; + } +}; + +template <class... Ts> +struct ParamTraits<mozilla::Variant<Ts...>> { + typedef mozilla::Variant<Ts...> paramType; + using Tag = typename mozilla::detail::VariantTag<Ts...>::Type; + + static void Write(Message* msg, const paramType& param) { + WriteParam(msg, param.tag); + param.match([msg](const auto& t) { WriteParam(msg, t); }); + } + + // Because VariantReader is a nested struct, we need the dummy template + // parameter to avoid making VariantReader<0> an explicit specialization, + // which is not allowed for a nested class template + template <size_t N, typename dummy = void> + struct VariantReader { + using Next = VariantReader<N - 1>; + + static bool Read(const Message* msg, PickleIterator* iter, Tag tag, + paramType* result) { + // Since the VariantReader specializations start at N , we need to + // subtract one to look at N - 1, the first valid tag. This means our + // comparisons are off by 1. If we get to N = 0 then we have failed to + // find a match to the tag. + if (tag == N - 1) { + // Recall, even though the template parameter is N, we are + // actually interested in the N - 1 tag. + // Default construct our field within the result outparameter and + // directly deserialize into the variant. Note that this means that + // every type in Ts needs to be default constructible + return ReadParam(msg, iter, &result->template emplace<N - 1>()); + } else { + return Next::Read(msg, iter, tag, result); + } + } + + }; // VariantReader<N> + + // Since we are conditioning on tag = N - 1 in the preceding specialization, + // if we get to `VariantReader<0, dummy>` we have failed to find + // a matching tag. + template <typename dummy> + struct VariantReader<0, dummy> { + static bool Read(const Message* msg, PickleIterator* iter, Tag tag, + paramType* result) { + return false; + } + }; + + static bool Read(const Message* msg, PickleIterator* iter, + paramType* result) { + Tag tag; + if (ReadParam(msg, iter, &tag)) { + return VariantReader<sizeof...(Ts)>::Read(msg, iter, tag, result); + } + return false; + } +}; + +template <typename T> +struct ParamTraits<mozilla::dom::Optional<T>> { + typedef mozilla::dom::Optional<T> paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + if (aParam.WasPassed()) { + WriteParam(aMsg, true); + WriteParam(aMsg, aParam.Value()); + return; + } + + WriteParam(aMsg, false); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + bool wasPassed = false; + + if (!ReadParam(aMsg, aIter, &wasPassed)) { + return false; + } + + aResult->Reset(); + + if (wasPassed) { + if (!ReadParam(aMsg, aIter, &aResult->Construct())) { + return false; + } + } + + return true; + } +}; + +struct CrossOriginOpenerPolicyValidator { + static bool IsLegalValue(nsILoadInfo::CrossOriginOpenerPolicy e) { + return e == nsILoadInfo::OPENER_POLICY_UNSAFE_NONE || + e == nsILoadInfo::OPENER_POLICY_SAME_ORIGIN || + e == nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_ALLOW_POPUPS || + e == nsILoadInfo:: + OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP; + } +}; + +template <> +struct ParamTraits<nsILoadInfo::CrossOriginOpenerPolicy> + : EnumSerializer<nsILoadInfo::CrossOriginOpenerPolicy, + CrossOriginOpenerPolicyValidator> {}; + +struct CrossOriginEmbedderPolicyValidator { + static bool IsLegalValue(nsILoadInfo::CrossOriginEmbedderPolicy e) { + return e == nsILoadInfo::EMBEDDER_POLICY_NULL || + e == nsILoadInfo::EMBEDDER_POLICY_REQUIRE_CORP; + } +}; + +template <> +struct ParamTraits<nsILoadInfo::CrossOriginEmbedderPolicy> + : EnumSerializer<nsILoadInfo::CrossOriginEmbedderPolicy, + CrossOriginEmbedderPolicyValidator> {}; + +template <size_t N, typename Word> +struct ParamTraits<mozilla::BitSet<N, Word>> { + typedef mozilla::BitSet<N, Word> paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + for (Word word : aParam.Storage()) { + WriteParam(aMsg, word); + } + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + for (Word& word : aResult->Storage()) { + if (!ReadParam(aMsg, aIter, &word)) { + return false; + } + } + return true; + } +}; + +} /* namespace IPC */ + +#endif /* __IPC_GLUE_IPCMESSAGEUTILSSPECIALIZATIONS_H__ */ |