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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_ipc_SidedVariant_h
8 #define mozilla_ipc_SidedVariant_h
11 #include "mozilla/Assertions.h"
12 #include "mozilla/Attributes.h"
13 #include "mozilla/ipc/ProtocolUtils.h"
14 #include "ipc/IPCMessageUtils.h"
20 * Helper type used by IPDL structs and unions to hold actor pointers with a
23 * When sent over IPC, ParentSide will be used for send/recv on parent actors,
24 * and ChildSide will be used for send/recv on child actors.
26 template <typename ParentSide
, typename ChildSide
>
29 SideVariant() = default;
31 std::enable_if_t
<std::is_convertible_v
<U
&&, ParentSide
>, int> = 0>
32 MOZ_IMPLICIT
SideVariant(U
&& aParent
) : mParent(std::forward
<U
>(aParent
)) {}
34 std::enable_if_t
<std::is_convertible_v
<U
&&, ChildSide
>, int> = 0>
35 MOZ_IMPLICIT
SideVariant(U
&& aChild
) : mChild(std::forward
<U
>(aChild
)) {}
36 MOZ_IMPLICIT
SideVariant(std::nullptr_t
) {}
38 MOZ_IMPLICIT SideVariant
& operator=(ParentSide aParent
) {
43 MOZ_IMPLICIT SideVariant
& operator=(ChildSide aChild
) {
48 MOZ_IMPLICIT SideVariant
& operator=(std::nullptr_t
) {
54 MOZ_IMPLICIT
operator bool() const { return mParent
|| mChild
; }
56 bool IsNull() const { return !operator bool(); }
57 bool IsParent() const { return mParent
; }
58 bool IsChild() const { return mChild
; }
60 ParentSide
AsParent() const {
61 MOZ_ASSERT(IsNull() || IsParent());
64 ChildSide
AsChild() const {
65 MOZ_ASSERT(IsNull() || IsChild());
70 // As the values are both pointers, this is the same size as a variant would
71 // be, but has less risk of type confusion, and supports an overall `nullptr`
72 // value which is neither parent nor child.
73 ParentSide mParent
= nullptr;
74 ChildSide mChild
= nullptr;
79 // NotNull specialization to expose AsChild and AsParent on the NotNull itself
80 // avoiding unnecessary unwrapping.
81 template <typename ParentSide
, typename ChildSide
>
82 class NotNull
<mozilla::ipc::SideVariant
<ParentSide
, ChildSide
>> {
84 friend constexpr NotNull
<U
> WrapNotNull(U aBasePtr
);
86 friend constexpr NotNull
<U
> WrapNotNullUnchecked(U aBasePtr
);
90 using BasePtr
= mozilla::ipc::SideVariant
<ParentSide
, ChildSide
>;
94 // This constructor is only used by WrapNotNull() and MakeNotNull<U>().
96 constexpr explicit NotNull(U aBasePtr
) : mBasePtr(aBasePtr
) {}
99 // Disallow default construction.
102 // Construct/assign from another NotNull with a compatible base pointer type.
103 template <typename U
, typename
= std::enable_if_t
<
104 std::is_convertible_v
<const U
&, BasePtr
>>>
105 constexpr MOZ_IMPLICIT
NotNull(const NotNull
<U
>& aOther
)
106 : mBasePtr(aOther
.get()) {
107 static_assert(sizeof(BasePtr
) == sizeof(NotNull
<BasePtr
>),
108 "NotNull must have zero space overhead.");
109 static_assert(offsetof(NotNull
<BasePtr
>, mBasePtr
) == 0,
110 "mBasePtr must have zero offset.");
113 template <typename U
,
114 typename
= std::enable_if_t
<std::is_convertible_v
<U
&&, BasePtr
>>>
115 constexpr MOZ_IMPLICIT
NotNull(MovingNotNull
<U
>&& aOther
)
116 : mBasePtr(NotNull
{std::move(aOther
)}) {}
118 // Disallow null checks, which are unnecessary for this type.
119 explicit operator bool() const = delete;
121 // Explicit conversion to a base pointer. Use only to resolve ambiguity or to
122 // get a castable pointer.
123 constexpr const BasePtr
& get() const { return mBasePtr
; }
125 // Implicit conversion to a base pointer. Preferable to get().
126 constexpr operator const BasePtr
&() const { return get(); }
128 bool IsParent() const { return get().IsParent(); }
129 bool IsChild() const { return get().IsChild(); }
131 NotNull
<ParentSide
> AsParent() const { return WrapNotNull(get().AsParent()); }
132 NotNull
<ChildSide
> AsChild() const { return WrapNotNull(get().AsChild()); }
135 } // namespace mozilla
139 template <typename ParentSide
, typename ChildSide
>
140 struct ParamTraits
<mozilla::ipc::SideVariant
<ParentSide
, ChildSide
>> {
141 typedef mozilla::ipc::SideVariant
<ParentSide
, ChildSide
> paramType
;
143 static void Write(IPC::MessageWriter
* aWriter
, const paramType
& aParam
) {
144 if (!aWriter
->GetActor()) {
145 aWriter
->FatalError("actor required to serialize this type");
149 if (aWriter
->GetActor()->GetSide() == mozilla::ipc::ParentSide
) {
150 if (aParam
&& !aParam
.IsParent()) {
151 aWriter
->FatalError("invalid side");
154 WriteParam(aWriter
, aParam
.AsParent());
156 if (aParam
&& !aParam
.IsChild()) {
157 aWriter
->FatalError("invalid side");
160 WriteParam(aWriter
, aParam
.AsChild());
164 static ReadResult
<paramType
> Read(IPC::MessageReader
* aReader
) {
165 if (!aReader
->GetActor()) {
166 aReader
->FatalError("actor required to deserialize this type");
170 if (aReader
->GetActor()->GetSide() == mozilla::ipc::ParentSide
) {
171 auto parentSide
= ReadParam
<ParentSide
>(aReader
);
175 return std::move(*parentSide
);
177 auto childSide
= ReadParam
<ChildSide
>(aReader
);
181 return std::move(*childSide
);
187 #endif // mozilla_ipc_SidedVariant_h