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>
13 #include "mozilla/TupleCycleCollection.h"
14 #include "mozilla/ResultExtensions.h"
15 #include "mozilla/dom/PromiseNativeHandler.h"
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
;
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
;
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
{
52 struct StorageTypeHelper
<T
, true, true> {
53 using Type
= nsCOMPtr
<T
>;
57 struct StorageTypeHelper
<nsCOMPtr
<T
>, true, true> {
58 using Type
= nsCOMPtr
<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
;
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
) {
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
{
98 NativeThenHandler(Promise
& aPromise
, Callback
&& aOnResolve
, Args
&&... aArgs
)
99 : PromiseNativeThenHandlerBase(aPromise
),
100 mOnResolve(std::forward
<Callback
>(aOnResolve
)),
101 mArgs(std::forward
<Args
>(aArgs
)...) {}
104 void Traverse(nsCycleCollectionTraversalCallback
& cb
) override
{
106 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArgs
)
109 void Unlink() override
{
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
...>{});
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
...>;
147 RefPtr
<Promise
> promise
= Promise::Create(GetParentObject(), rv
);
149 return Err(rv
.StealNSResult());
153 new (fallible
) HandlerType(*promise
, std::forward
<Callback
>(aOnResolve
),
154 std::forward
<Args
>(aArgs
)...);
157 return Err(NS_ERROR_OUT_OF_MEMORY
);
160 AppendNativeHandler(handler
);
161 return std::move(promise
);
165 } // namespace mozilla
167 #endif // mozilla_dom_Promise_inl_h