tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SideVariant.h (6068B)


      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/. */
      6 
      7 #ifndef mozilla_ipc_SidedVariant_h
      8 #define mozilla_ipc_SidedVariant_h
      9 
     10 #include <variant>
     11 #include "mozilla/Assertions.h"
     12 #include "mozilla/Attributes.h"
     13 #include "mozilla/ipc/ProtocolUtils.h"
     14 #include "ipc/IPCMessageUtils.h"
     15 
     16 namespace mozilla {
     17 namespace ipc {
     18 
     19 /**
     20 * Helper type used by IPDL structs and unions to hold actor pointers with a
     21 * dynamic side.
     22 *
     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.
     25 */
     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) {}
     37 
     38  MOZ_IMPLICIT SideVariant& operator=(ParentSide aParent) {
     39    mParent = aParent;
     40    mChild = nullptr;
     41    return *this;
     42  }
     43  MOZ_IMPLICIT SideVariant& operator=(ChildSide aChild) {
     44    mChild = aChild;
     45    mParent = nullptr;
     46    return *this;
     47  }
     48  MOZ_IMPLICIT SideVariant& operator=(std::nullptr_t) {
     49    mChild = nullptr;
     50    mParent = nullptr;
     51    return *this;
     52  }
     53 
     54  MOZ_IMPLICIT operator bool() const { return mParent || mChild; }
     55 
     56  bool IsNull() const { return !operator bool(); }
     57  bool IsParent() const { return mParent; }
     58  bool IsChild() const { return mChild; }
     59 
     60  ParentSide AsParent() const {
     61    MOZ_ASSERT(IsNull() || IsParent());
     62    return mParent;
     63  }
     64  ChildSide AsChild() const {
     65    MOZ_ASSERT(IsNull() || IsChild());
     66    return mChild;
     67  }
     68 
     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;
     75 };
     76 
     77 }  // namespace ipc
     78 
     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;
     89 
     90  using BasePtr = mozilla::ipc::SideVariant<ParentSide, ChildSide>;
     91 
     92  BasePtr mBasePtr;
     93 
     94  // This constructor is only used by WrapNotNull() and MakeNotNull<U>().
     95  template <typename U>
     96  constexpr explicit NotNull(U aBasePtr) : mBasePtr(aBasePtr) {}
     97 
     98 public:
     99  // Disallow default construction.
    100  NotNull() = delete;
    101 
    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.");
    111  }
    112 
    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)}) {}
    117 
    118  // Disallow null checks, which are unnecessary for this type.
    119  explicit operator bool() const = delete;
    120 
    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; }
    124 
    125  // Implicit conversion to a base pointer. Preferable to get().
    126  constexpr operator const BasePtr&() const { return get(); }
    127 
    128  bool IsParent() const { return get().IsParent(); }
    129  bool IsChild() const { return get().IsChild(); }
    130 
    131  NotNull<ParentSide> AsParent() const { return WrapNotNull(get().AsParent()); }
    132  NotNull<ChildSide> AsChild() const { return WrapNotNull(get().AsChild()); }
    133 };
    134 
    135 }  // namespace mozilla
    136 
    137 namespace IPC {
    138 
    139 template <typename ParentSide, typename ChildSide>
    140 struct ParamTraits<mozilla::ipc::SideVariant<ParentSide, ChildSide>> {
    141  typedef mozilla::ipc::SideVariant<ParentSide, ChildSide> paramType;
    142 
    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;
    147    }
    148 
    149    if (aWriter->GetActor()->GetSide() == mozilla::ipc::ParentSide) {
    150      if (aParam && !aParam.IsParent()) {
    151        aWriter->FatalError("invalid side");
    152        return;
    153      }
    154      WriteParam(aWriter, aParam.AsParent());
    155    } else {
    156      if (aParam && !aParam.IsChild()) {
    157        aWriter->FatalError("invalid side");
    158        return;
    159      }
    160      WriteParam(aWriter, aParam.AsChild());
    161    }
    162  }
    163 
    164  static ReadResult<paramType> Read(IPC::MessageReader* aReader) {
    165    if (!aReader->GetActor()) {
    166      aReader->FatalError("actor required to deserialize this type");
    167      return {};
    168    }
    169 
    170    if (aReader->GetActor()->GetSide() == mozilla::ipc::ParentSide) {
    171      auto parentSide = ReadParam<ParentSide>(aReader);
    172      if (!parentSide) {
    173        return {};
    174      }
    175      return std::move(*parentSide);
    176    }
    177    auto childSide = ReadParam<ChildSide>(aReader);
    178    if (!childSide) {
    179      return {};
    180    }
    181    return std::move(*childSide);
    182  }
    183 };
    184 
    185 }  // namespace IPC
    186 
    187 #endif  // mozilla_ipc_SidedVariant_h