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 "mozilla/TupleCycleCollection.h"
11 #include "mozilla/TypeTraits.h"
12 #include "mozilla/ResultExtensions.h"
13 #include "mozilla/dom/PromiseNativeHandler.h"
18 class PromiseNativeThenHandlerBase
: public PromiseNativeHandler
{
19 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
20 NS_DECL_CYCLE_COLLECTION_CLASS(PromiseNativeThenHandlerBase
)
22 PromiseNativeThenHandlerBase(Promise
& aPromise
) : mPromise(&aPromise
) {}
24 void ResolvedCallback(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
) override
;
26 void RejectedCallback(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
) override
;
29 virtual ~PromiseNativeThenHandlerBase() = default;
31 virtual already_AddRefed
<Promise
> CallResolveCallback(
32 JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
) = 0;
34 virtual void Traverse(nsCycleCollectionTraversalCallback
&) = 0;
35 virtual void Unlink() = 0;
37 RefPtr
<Promise
> mPromise
;
43 bool = IsRefcounted
<typename RemovePointer
<T
>::Type
>::value
,
44 bool = (IsConvertible
<T
, nsISupports
*>::value
||
45 IsConvertible
<T
*, nsISupports
*>::value
)>
46 struct StorageTypeHelper
{
51 struct StorageTypeHelper
<T
, true, true> {
52 using Type
= nsCOMPtr
<T
>;
56 struct StorageTypeHelper
<nsCOMPtr
<T
>, true, true> {
57 using Type
= nsCOMPtr
<T
>;
61 struct StorageTypeHelper
<T
*, true, false> {
62 using Type
= RefPtr
<T
>;
65 template <template <typename
> class SmartPtr
, typename T
>
66 struct StorageTypeHelper
<SmartPtr
<T
>, true, false>
67 : EnableIf
<IsConvertible
<SmartPtr
<T
>, T
*>::value
, RefPtr
<T
>> {};
70 using StorageType
= typename StorageTypeHelper
<typename Decay
<T
>::Type
>::Type
;
72 // Helpers to choose the correct argument type based on the storage type. Smart
73 // pointers are converted to the corresponding raw pointer type. Everything else
74 // is passed by move reference.
76 // Note: We can't just use std::forward for this because the input type may be a
77 // raw pointer which does not match the argument type, and while the
78 // spec-compliant behavior there should still give us the expected results, MSVC
79 // considers it an illegal use of std::forward.
80 template <template <typename
> class SmartPtr
, typename T
>
81 decltype(DeclVal
<SmartPtr
<T
>>().get()) ArgType(SmartPtr
<T
>& aVal
) {
86 T
&& ArgType(T
& aVal
) {
87 return std::move(aVal
);
90 using ::ImplCycleCollectionUnlink
;
92 template <typename Callback
, typename
... Args
>
93 class NativeThenHandler final
: public PromiseNativeThenHandlerBase
{
95 NativeThenHandler(Promise
& aPromise
, Callback
&& aOnResolve
, Args
&&... aArgs
)
96 : PromiseNativeThenHandlerBase(aPromise
),
97 mOnResolve(std::forward
<Callback
>(aOnResolve
)),
98 mArgs(std::forward
<Args
>(aArgs
)...) {}
101 void Traverse(nsCycleCollectionTraversalCallback
& cb
) override
{
103 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArgs
)
106 void Unlink() override
{
108 NS_IMPL_CYCLE_COLLECTION_UNLINK(mArgs
)
111 already_AddRefed
<Promise
> CallResolveCallback(
112 JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
) override
{
113 return CallCallback(aCx
, mOnResolve
, aValue
);
116 template <size_t... Indices
>
117 already_AddRefed
<Promise
> CallCallback(JSContext
* aCx
,
118 const Callback
& aHandler
,
119 JS::Handle
<JS::Value
> aValue
,
120 std::index_sequence
<Indices
...>) {
121 return mOnResolve(aCx
, aValue
, ArgType(Get
<Indices
>(mArgs
))...);
124 already_AddRefed
<Promise
> CallCallback(JSContext
* aCx
,
125 const Callback
& aHandler
,
126 JS::Handle
<JS::Value
> aValue
) {
127 return CallCallback(aCx
, aHandler
, aValue
,
128 std::index_sequence_for
<Args
...>{});
133 Tuple
<StorageType
<Args
>...> mArgs
;
136 } // anonymous namespace
138 template <typename Callback
, typename
... Args
>
139 Promise::ThenResult
<Callback
, Args
...> Promise::ThenWithCycleCollectedArgs(
140 Callback
&& aOnResolve
, Args
&&... aArgs
) {
141 using HandlerType
= NativeThenHandler
<Callback
, Args
...>;
144 RefPtr
<Promise
> promise
= Promise::Create(GetParentObject(), rv
);
146 return Err(rv
.StealNSResult());
150 new (fallible
) HandlerType(*promise
, std::forward
<Callback
>(aOnResolve
),
151 std::forward
<Args
>(aArgs
)...);
154 return Err(NS_ERROR_OUT_OF_MEMORY
);
157 AppendNativeHandler(handler
);
158 return std::move(promise
);
162 } // namespace mozilla
164 #endif // mozilla_dom_Promise_inl_h