Bug 1700051: part 26) Correct typo in comment of `mozInlineSpellWordUtil::BuildSoftTe...
[gecko.git] / dom / promise / Promise-inl.h
blob4ff32585babb1870c0591298812511c2f74366fd
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_dom_Promise_inl_h
8 #define mozilla_dom_Promise_inl_h
10 #include <type_traits>
11 #include <utility>
13 #include "mozilla/TupleCycleCollection.h"
14 #include "mozilla/ResultExtensions.h"
15 #include "mozilla/dom/PromiseNativeHandler.h"
17 namespace mozilla {
18 namespace dom {
20 class PromiseNativeThenHandlerBase : public PromiseNativeHandler {
21 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
22 NS_DECL_CYCLE_COLLECTION_CLASS(PromiseNativeThenHandlerBase)
24 PromiseNativeThenHandlerBase(Promise& aPromise) : mPromise(&aPromise) {}
26 void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
28 void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
30 protected:
31 virtual ~PromiseNativeThenHandlerBase() = default;
33 virtual already_AddRefed<Promise> CallResolveCallback(
34 JSContext* aCx, JS::Handle<JS::Value> aValue) = 0;
36 virtual void Traverse(nsCycleCollectionTraversalCallback&) = 0;
37 virtual void Unlink() = 0;
39 RefPtr<Promise> mPromise;
42 namespace {
44 template <typename T, bool = IsRefcounted<std::remove_pointer_t<T>>::value,
45 bool = (std::is_convertible_v<T, nsISupports*> ||
46 std::is_convertible_v<T*, nsISupports*>)>
47 struct StorageTypeHelper {
48 using Type = T;
51 template <typename T>
52 struct StorageTypeHelper<T, true, true> {
53 using Type = nsCOMPtr<T>;
56 template <typename T>
57 struct StorageTypeHelper<nsCOMPtr<T>, true, true> {
58 using Type = nsCOMPtr<T>;
61 template <typename T>
62 struct StorageTypeHelper<T*, true, false> {
63 using Type = RefPtr<T>;
66 template <template <typename> class SmartPtr, typename T>
67 struct StorageTypeHelper<SmartPtr<T>, true, false>
68 : std::enable_if<std::is_convertible_v<SmartPtr<T>, T*>, RefPtr<T>> {
69 using Type = typename StorageTypeHelper::enable_if::type;
72 template <typename T>
73 using StorageType = typename StorageTypeHelper<std::decay_t<T>>::Type;
75 // Helpers to choose the correct argument type based on the storage type. Smart
76 // pointers are converted to the corresponding raw pointer type. Everything else
77 // is passed by move reference.
79 // Note: We can't just use std::forward for this because the input type may be a
80 // raw pointer which does not match the argument type, and while the
81 // spec-compliant behavior there should still give us the expected results, MSVC
82 // considers it an illegal use of std::forward.
83 template <template <typename> class SmartPtr, typename T>
84 decltype(std::declval<SmartPtr<T>>().get()) ArgType(SmartPtr<T>& aVal) {
85 return aVal.get();
88 template <typename T>
89 T&& ArgType(T& aVal) {
90 return std::move(aVal);
93 using ::ImplCycleCollectionUnlink;
95 template <typename Callback, typename... Args>
96 class NativeThenHandler final : public PromiseNativeThenHandlerBase {
97 public:
98 NativeThenHandler(Promise& aPromise, Callback&& aOnResolve, Args&&... aArgs)
99 : PromiseNativeThenHandlerBase(aPromise),
100 mOnResolve(std::forward<Callback>(aOnResolve)),
101 mArgs(std::forward<Args>(aArgs)...) {}
103 protected:
104 void Traverse(nsCycleCollectionTraversalCallback& cb) override {
105 auto* tmp = this;
106 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArgs)
109 void Unlink() override {
110 auto* tmp = this;
111 NS_IMPL_CYCLE_COLLECTION_UNLINK(mArgs)
114 already_AddRefed<Promise> CallResolveCallback(
115 JSContext* aCx, JS::Handle<JS::Value> aValue) override {
116 return CallCallback(aCx, mOnResolve, aValue);
119 template <size_t... Indices>
120 already_AddRefed<Promise> CallCallback(JSContext* aCx,
121 const Callback& aHandler,
122 JS::Handle<JS::Value> aValue,
123 std::index_sequence<Indices...>) {
124 return mOnResolve(aCx, aValue, ArgType(Get<Indices>(mArgs))...);
127 already_AddRefed<Promise> CallCallback(JSContext* aCx,
128 const Callback& aHandler,
129 JS::Handle<JS::Value> aValue) {
130 return CallCallback(aCx, aHandler, aValue,
131 std::index_sequence_for<Args...>{});
134 Callback mOnResolve;
136 Tuple<StorageType<Args>...> mArgs;
139 } // anonymous namespace
141 template <typename Callback, typename... Args>
142 Promise::ThenResult<Callback, Args...> Promise::ThenWithCycleCollectedArgs(
143 Callback&& aOnResolve, Args&&... aArgs) {
144 using HandlerType = NativeThenHandler<Callback, Args...>;
146 ErrorResult rv;
147 RefPtr<Promise> promise = Promise::Create(GetParentObject(), rv);
148 if (rv.Failed()) {
149 return Err(rv.StealNSResult());
152 auto* handler =
153 new (fallible) HandlerType(*promise, std::forward<Callback>(aOnResolve),
154 std::forward<Args>(aArgs)...);
156 if (!handler) {
157 return Err(NS_ERROR_OUT_OF_MEMORY);
160 AppendNativeHandler(handler);
161 return std::move(promise);
164 } // namespace dom
165 } // namespace mozilla
167 #endif // mozilla_dom_Promise_inl_h