Skip to content

Commit

Permalink
Bug 1607634 - Part 3: Specialize NotNull for SideVariant, r=glandium,…
Browse files Browse the repository at this point in the history
…ipc-reviewers,mccr8

The idea behind this specialization is to provide the members which would be on
SideVariant<..> on NotNull<SideVariant<..>>, similar to how pointer-like
methods are available on `NotNull<T>`. This makes the type more ergonomic to
use from callers.

In the next part, this will be used for non-nullable actor members in IPDL
structs and IPDL unions.

Differential Revision: https://phabricator.services.mozilla.com/D168885
  • Loading branch information
mystor committed Mar 20, 2023
1 parent aa58ee3 commit 2c767a1
Showing 1 changed file with 61 additions and 3 deletions.
64 changes: 61 additions & 3 deletions ipc/glue/SideVariant.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
#include "mozilla/ipc/ProtocolUtils.h"
#include "ipc/IPCMessageUtils.h"

namespace mozilla::ipc {
namespace mozilla {
namespace ipc {

/**
* Helper type used by IPDL structs and unions to hold actor pointers with a
Expand All @@ -24,7 +25,6 @@ namespace mozilla::ipc {
*/
template <typename ParentSide, typename ChildSide>
struct SideVariant {
private:
public:
SideVariant() = default;
template <typename U,
Expand Down Expand Up @@ -74,7 +74,65 @@ struct SideVariant {
ChildSide mChild = nullptr;
};

} // namespace mozilla::ipc
} // 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 {

Expand Down

0 comments on commit 2c767a1

Please sign in to comment.