1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 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
|