Bug 1858509 add thread-safety annotations around MediaSourceDemuxer::mMonitor r=alwu
[gecko.git] / ipc / glue / SideVariant.h
blob3082feebde3043ad597350d16b132500b51058c2
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
10 #include <variant>
11 #include "mozilla/Assertions.h"
12 #include "mozilla/Attributes.h"
13 #include "mozilla/ipc/ProtocolUtils.h"
14 #include "ipc/IPCMessageUtils.h"
16 namespace mozilla {
17 namespace ipc {
19 /**
20 * Helper type used by IPDL structs and unions to hold actor pointers with a
21 * dynamic side.
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>
27 struct SideVariant {
28 public:
29 SideVariant() = default;
30 template <typename U,
31 std::enable_if_t<std::is_convertible_v<U&&, ParentSide>, int> = 0>
32 MOZ_IMPLICIT SideVariant(U&& aParent) : mParent(std::forward<U>(aParent)) {}
33 template <typename U,
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) {
39 mParent = aParent;
40 mChild = nullptr;
41 return *this;
43 MOZ_IMPLICIT SideVariant& operator=(ChildSide aChild) {
44 mChild = aChild;
45 mParent = nullptr;
46 return *this;
48 MOZ_IMPLICIT SideVariant& operator=(std::nullptr_t) {
49 mChild = nullptr;
50 mParent = nullptr;
51 return *this;
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());
62 return mParent;
64 ChildSide AsChild() const {
65 MOZ_ASSERT(IsNull() || IsChild());
66 return mChild;
69 private:
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;
77 } // namespace ipc
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>> {
83 template <typename U>
84 friend constexpr NotNull<U> WrapNotNull(U aBasePtr);
85 template <typename U>
86 friend constexpr NotNull<U> WrapNotNullUnchecked(U aBasePtr);
87 template <typename U>
88 friend class NotNull;
90 using BasePtr = mozilla::ipc::SideVariant<ParentSide, ChildSide>;
92 BasePtr mBasePtr;
94 // This constructor is only used by WrapNotNull() and MakeNotNull<U>().
95 template <typename U>
96 constexpr explicit NotNull(U aBasePtr) : mBasePtr(aBasePtr) {}
98 public:
99 // Disallow default construction.
100 NotNull() = delete;
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
137 namespace IPC {
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");
146 return;
149 if (aWriter->GetActor()->GetSide() == mozilla::ipc::ParentSide) {
150 if (aParam && !aParam.IsParent()) {
151 aWriter->FatalError("invalid side");
152 return;
154 WriteParam(aWriter, aParam.AsParent());
155 } else {
156 if (aParam && !aParam.IsChild()) {
157 aWriter->FatalError("invalid side");
158 return;
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");
167 return {};
170 if (aReader->GetActor()->GetSide() == mozilla::ipc::ParentSide) {
171 auto parentSide = ReadParam<ParentSide>(aReader);
172 if (!parentSide) {
173 return {};
175 return std::move(*parentSide);
177 auto childSide = ReadParam<ChildSide>(aReader);
178 if (!childSide) {
179 return {};
181 return std::move(*childSide);
185 } // namespace IPC
187 #endif // mozilla_ipc_SidedVariant_h