diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:44:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:44:51 +0000 |
commit | 9e3c08db40b8916968b9f30096c7be3f00ce9647 (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /ipc/glue/SideVariant.h | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ipc/glue/SideVariant.h')
-rw-r--r-- | ipc/glue/SideVariant.h | 187 |
1 files changed, 187 insertions, 0 deletions
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 <variant> +#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 <typename ParentSide, typename ChildSide> +struct SideVariant { + public: + SideVariant() = default; + template <typename U, + std::enable_if_t<std::is_convertible_v<U&&, ParentSide>, int> = 0> + MOZ_IMPLICIT SideVariant(U&& aParent) : mParent(std::forward<U>(aParent)) {} + template <typename U, + std::enable_if_t<std::is_convertible_v<U&&, ChildSide>, int> = 0> + MOZ_IMPLICIT SideVariant(U&& aChild) : mChild(std::forward<U>(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 <typename ParentSide, typename ChildSide> +class NotNull<mozilla::ipc::SideVariant<ParentSide, ChildSide>> { + template <typename U> + friend constexpr NotNull<U> WrapNotNull(U aBasePtr); + template <typename U> + friend constexpr NotNull<U> WrapNotNullUnchecked(U aBasePtr); + template <typename U> + friend class NotNull; + + using BasePtr = mozilla::ipc::SideVariant<ParentSide, ChildSide>; + + BasePtr mBasePtr; + + // This constructor is only used by WrapNotNull() and MakeNotNull<U>(). + template <typename U> + 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 <typename U, typename = std::enable_if_t< + std::is_convertible_v<const U&, BasePtr>>> + constexpr MOZ_IMPLICIT NotNull(const NotNull<U>& aOther) + : mBasePtr(aOther.get()) { + static_assert(sizeof(BasePtr) == sizeof(NotNull<BasePtr>), + "NotNull must have zero space overhead."); + static_assert(offsetof(NotNull<BasePtr>, mBasePtr) == 0, + "mBasePtr must have zero offset."); + } + + template <typename U, + typename = std::enable_if_t<std::is_convertible_v<U&&, BasePtr>>> + constexpr MOZ_IMPLICIT NotNull(MovingNotNull<U>&& 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<ParentSide> AsParent() const { return WrapNotNull(get().AsParent()); } + NotNull<ChildSide> AsChild() const { return WrapNotNull(get().AsChild()); } +}; + +} // namespace mozilla + +namespace IPC { + +template <typename ParentSide, typename ChildSide> +struct ParamTraits<mozilla::ipc::SideVariant<ParentSide, ChildSide>> { + typedef mozilla::ipc::SideVariant<ParentSide, ChildSide> 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<paramType> 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<ParentSide>(aReader); + if (!parentSide) { + return {}; + } + return std::move(*parentSide); + } + auto childSide = ReadParam<ChildSide>(aReader); + if (!childSide) { + return {}; + } + return std::move(*childSide); + } +}; + +} // namespace IPC + +#endif // mozilla_ipc_SidedVariant_h |