From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- ipc/glue/SideVariant.h | 187 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 ipc/glue/SideVariant.h (limited to 'ipc/glue/SideVariant.h') diff --git a/ipc/glue/SideVariant.h b/ipc/glue/SideVariant.h new file mode 100644 index 0000000000..3082feebde --- /dev/null +++ b/ipc/glue/SideVariant.h @@ -0,0 +1,187 @@ +/* -*- 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 mozilla_ipc_SidedVariant_h +#define mozilla_ipc_SidedVariant_h + +#include +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/ipc/ProtocolUtils.h" +#include "ipc/IPCMessageUtils.h" + +namespace mozilla { +namespace ipc { + +/** + * Helper type used by IPDL structs and unions to hold actor pointers with a + * dynamic side. + * + * When sent over IPC, ParentSide will be used for send/recv on parent actors, + * and ChildSide will be used for send/recv on child actors. + */ +template +struct SideVariant { + public: + SideVariant() = default; + template , int> = 0> + MOZ_IMPLICIT SideVariant(U&& aParent) : mParent(std::forward(aParent)) {} + template , int> = 0> + MOZ_IMPLICIT SideVariant(U&& aChild) : mChild(std::forward(aChild)) {} + MOZ_IMPLICIT SideVariant(std::nullptr_t) {} + + MOZ_IMPLICIT SideVariant& operator=(ParentSide aParent) { + mParent = aParent; + mChild = nullptr; + return *this; + } + MOZ_IMPLICIT SideVariant& operator=(ChildSide aChild) { + mChild = aChild; + mParent = nullptr; + return *this; + } + MOZ_IMPLICIT SideVariant& operator=(std::nullptr_t) { + mChild = nullptr; + mParent = nullptr; + return *this; + } + + MOZ_IMPLICIT operator bool() const { return mParent || mChild; } + + bool IsNull() const { return !operator bool(); } + bool IsParent() const { return mParent; } + bool IsChild() const { return mChild; } + + ParentSide AsParent() const { + MOZ_ASSERT(IsNull() || IsParent()); + return mParent; + } + ChildSide AsChild() const { + MOZ_ASSERT(IsNull() || IsChild()); + return mChild; + } + + private: + // As the values are both pointers, this is the same size as a variant would + // be, but has less risk of type confusion, and supports an overall `nullptr` + // value which is neither parent nor child. + ParentSide mParent = nullptr; + ChildSide mChild = nullptr; +}; + +} // namespace ipc + +// NotNull specialization to expose AsChild and AsParent on the NotNull itself +// avoiding unnecessary unwrapping. +template +class NotNull> { + template + friend constexpr NotNull WrapNotNull(U aBasePtr); + template + friend constexpr NotNull WrapNotNullUnchecked(U aBasePtr); + template + friend class NotNull; + + using BasePtr = mozilla::ipc::SideVariant; + + BasePtr mBasePtr; + + // This constructor is only used by WrapNotNull() and MakeNotNull(). + template + constexpr explicit NotNull(U aBasePtr) : mBasePtr(aBasePtr) {} + + public: + // Disallow default construction. + NotNull() = delete; + + // Construct/assign from another NotNull with a compatible base pointer type. + template >> + constexpr MOZ_IMPLICIT NotNull(const NotNull& aOther) + : mBasePtr(aOther.get()) { + static_assert(sizeof(BasePtr) == sizeof(NotNull), + "NotNull must have zero space overhead."); + static_assert(offsetof(NotNull, mBasePtr) == 0, + "mBasePtr must have zero offset."); + } + + template >> + constexpr MOZ_IMPLICIT NotNull(MovingNotNull&& aOther) + : mBasePtr(NotNull{std::move(aOther)}) {} + + // Disallow null checks, which are unnecessary for this type. + explicit operator bool() const = delete; + + // Explicit conversion to a base pointer. Use only to resolve ambiguity or to + // get a castable pointer. + constexpr const BasePtr& get() const { return mBasePtr; } + + // Implicit conversion to a base pointer. Preferable to get(). + constexpr operator const BasePtr&() const { return get(); } + + bool IsParent() const { return get().IsParent(); } + bool IsChild() const { return get().IsChild(); } + + NotNull AsParent() const { return WrapNotNull(get().AsParent()); } + NotNull AsChild() const { return WrapNotNull(get().AsChild()); } +}; + +} // namespace mozilla + +namespace IPC { + +template +struct ParamTraits> { + typedef mozilla::ipc::SideVariant paramType; + + static void Write(IPC::MessageWriter* aWriter, const paramType& aParam) { + if (!aWriter->GetActor()) { + aWriter->FatalError("actor required to serialize this type"); + return; + } + + if (aWriter->GetActor()->GetSide() == mozilla::ipc::ParentSide) { + if (aParam && !aParam.IsParent()) { + aWriter->FatalError("invalid side"); + return; + } + WriteParam(aWriter, aParam.AsParent()); + } else { + if (aParam && !aParam.IsChild()) { + aWriter->FatalError("invalid side"); + return; + } + WriteParam(aWriter, aParam.AsChild()); + } + } + + static ReadResult Read(IPC::MessageReader* aReader) { + if (!aReader->GetActor()) { + aReader->FatalError("actor required to deserialize this type"); + return {}; + } + + if (aReader->GetActor()->GetSide() == mozilla::ipc::ParentSide) { + auto parentSide = ReadParam(aReader); + if (!parentSide) { + return {}; + } + return std::move(*parentSide); + } + auto childSide = ReadParam(aReader); + if (!childSide) { + return {}; + } + return std::move(*childSide); + } +}; + +} // namespace IPC + +#endif // mozilla_ipc_SidedVariant_h -- cgit v1.2.3