summaryrefslogtreecommitdiffstats
path: root/xpcom/threads/MozPromise.h
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/threads/MozPromise.h')
-rw-r--r--xpcom/threads/MozPromise.h200
1 files changed, 85 insertions, 115 deletions
diff --git a/xpcom/threads/MozPromise.h b/xpcom/threads/MozPromise.h
index f17e085c2f..af4ac657fd 100644
--- a/xpcom/threads/MozPromise.h
+++ b/xpcom/threads/MozPromise.h
@@ -82,24 +82,22 @@ struct MethodTrait : MethodTraitsHelper<std::remove_reference_t<T>> {};
} // namespace detail
-template <typename MethodType>
-using TakesArgument =
- std::integral_constant<bool, detail::MethodTrait<MethodType>::ArgSize != 0>;
+template <typename T>
+using MethodReturnType = typename detail::MethodTrait<T>::ReturnType;
-template <typename MethodType, typename TargetType>
-using ReturnTypeIs =
- std::is_convertible<typename detail::MethodTrait<MethodType>::ReturnType,
- TargetType>;
+template <typename MethodType>
+constexpr bool TakesAnyArguments =
+ detail::MethodTrait<MethodType>::ArgSize != 0;
template <typename ResolveValueT, typename RejectValueT, bool IsExclusive>
class MozPromise;
-template <typename Return>
-struct IsMozPromise : std::false_type {};
+template <typename T>
+constexpr bool IsMozPromise = false;
template <typename ResolveValueT, typename RejectValueT, bool IsExclusive>
-struct IsMozPromise<MozPromise<ResolveValueT, RejectValueT, IsExclusive>>
- : std::true_type {};
+constexpr bool
+ IsMozPromise<MozPromise<ResolveValueT, RejectValueT, IsExclusive>> = true;
/*
* A promise manages an asynchronous request that may or may not be able to be
@@ -176,8 +174,8 @@ class MozPromise : public MozPromiseBase {
}
public:
- typedef ResolveValueT ResolveValueType;
- typedef RejectValueT RejectValueType;
+ using ResolveValueType = ResolveValueT;
+ using RejectValueType = RejectValueT;
class ResolveOrRejectValue {
public:
template <typename ResolveValueType_>
@@ -288,12 +286,10 @@ class MozPromise : public MozPromiseBase {
return p;
}
- typedef MozPromise<CopyableTArray<ResolveValueType>, RejectValueType,
- IsExclusive>
- AllPromiseType;
-
- typedef MozPromise<CopyableTArray<ResolveOrRejectValue>, bool, IsExclusive>
- AllSettledPromiseType;
+ using AllPromiseType = MozPromise<CopyableTArray<ResolveValueType>,
+ RejectValueType, IsExclusive>;
+ using AllSettledPromiseType =
+ MozPromise<CopyableTArray<ResolveOrRejectValue>, bool, IsExclusive>;
private:
class AllPromiseHolder : public MozPromiseRefcountable {
@@ -350,17 +346,17 @@ class MozPromise : public MozPromiseBase {
// Trying to pass ResolveOrRejectValue by value fails static analysis checks,
// so we need to use either a const& or an rvalue reference, depending on
// whether IsExclusive is true or not.
- typedef std::conditional_t<IsExclusive, ResolveOrRejectValue&&,
- const ResolveOrRejectValue&>
- ResolveOrRejectValueParam;
+ using ResolveOrRejectValueParam =
+ std::conditional_t<IsExclusive, ResolveOrRejectValue&&,
+ const ResolveOrRejectValue&>;
- typedef std::conditional_t<IsExclusive, ResolveValueType&&,
- const ResolveValueType&>
- ResolveValueTypeParam;
+ using ResolveValueTypeParam =
+ std::conditional_t<IsExclusive, ResolveValueType&&,
+ const ResolveValueType&>;
- typedef std::conditional_t<IsExclusive, RejectValueType&&,
- const RejectValueType&>
- RejectValueTypeParam;
+ using RejectValueTypeParam =
+ std::conditional_t<IsExclusive, RejectValueType&&,
+ const RejectValueType&>;
class AllSettledPromiseHolder : public MozPromiseRefcountable {
public:
@@ -648,15 +644,15 @@ class MozPromise : public MozPromiseBase {
* make the resolve/reject value argument "optional".
*/
template <typename ThisType, typename MethodType, typename ValueType>
- static std::enable_if_t<TakesArgument<MethodType>::value,
- typename detail::MethodTrait<MethodType>::ReturnType>
+ static std::enable_if_t<TakesAnyArguments<MethodType>,
+ MethodReturnType<MethodType>>
InvokeMethod(ThisType* aThisVal, MethodType aMethod, ValueType&& aValue) {
return (aThisVal->*aMethod)(std::forward<ValueType>(aValue));
}
template <typename ThisType, typename MethodType, typename ValueType>
- static std::enable_if_t<!TakesArgument<MethodType>::value,
- typename detail::MethodTrait<MethodType>::ReturnType>
+ static std::enable_if_t<!TakesAnyArguments<MethodType>,
+ MethodReturnType<MethodType>>
InvokeMethod(ThisType* aThisVal, MethodType aMethod, ValueType&& aValue) {
return (aThisVal->*aMethod)();
}
@@ -697,18 +693,14 @@ class MozPromise : public MozPromiseBase {
: public ThenValueBase {
friend class ThenCommand<ThenValue>;
- using R1 = typename RemoveSmartPointer<
- typename detail::MethodTrait<ResolveMethodType>::ReturnType>::Type;
- using R2 = typename RemoveSmartPointer<
- typename detail::MethodTrait<RejectMethodType>::ReturnType>::Type;
- using SupportChaining =
- std::integral_constant<bool, IsMozPromise<R1>::value &&
- std::is_same_v<R1, R2>>;
+ using R1 = RemoveSmartPointer<MethodReturnType<ResolveMethodType>>;
+ using R2 = RemoveSmartPointer<MethodReturnType<RejectMethodType>>;
+ constexpr static bool SupportChaining =
+ IsMozPromise<R1> && std::is_same_v<R1, R2>;
// Fall back to MozPromise when promise chaining is not supported to make
// code compile.
- using PromiseType =
- std::conditional_t<SupportChaining::value, R1, MozPromise>;
+ using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>;
public:
ThenValue(nsISerialEventTarget* aResponseTarget, ThisType* aThisVal,
@@ -736,13 +728,13 @@ class MozPromise : public MozPromiseBase {
void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override {
if (aValue.IsResolve()) {
- InvokeCallbackMethod<SupportChaining::value>(
- mThisVal.get(), mResolveMethod, MaybeMove(aValue.ResolveValue()),
- std::move(mCompletionPromise));
+ InvokeCallbackMethod<SupportChaining>(mThisVal.get(), mResolveMethod,
+ MaybeMove(aValue.ResolveValue()),
+ std::move(mCompletionPromise));
} else {
- InvokeCallbackMethod<SupportChaining::value>(
- mThisVal.get(), mRejectMethod, MaybeMove(aValue.RejectValue()),
- std::move(mCompletionPromise));
+ InvokeCallbackMethod<SupportChaining>(mThisVal.get(), mRejectMethod,
+ MaybeMove(aValue.RejectValue()),
+ std::move(mCompletionPromise));
}
// Null out mThisVal after invoking the callback so that any references
@@ -764,15 +756,12 @@ class MozPromise : public MozPromiseBase {
class ThenValue<ThisType*, ResolveRejectMethodType> : public ThenValueBase {
friend class ThenCommand<ThenValue>;
- using R1 = typename RemoveSmartPointer<typename detail::MethodTrait<
- ResolveRejectMethodType>::ReturnType>::Type;
- using SupportChaining =
- std::integral_constant<bool, IsMozPromise<R1>::value>;
+ using R1 = RemoveSmartPointer<MethodReturnType<ResolveRejectMethodType>>;
+ constexpr static bool SupportChaining = IsMozPromise<R1>;
// Fall back to MozPromise when promise chaining is not supported to make
// code compile.
- using PromiseType =
- std::conditional_t<SupportChaining::value, R1, MozPromise>;
+ using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>;
public:
ThenValue(nsISerialEventTarget* aResponseTarget, ThisType* aThisVal,
@@ -798,7 +787,7 @@ class MozPromise : public MozPromiseBase {
}
void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override {
- InvokeCallbackMethod<SupportChaining::value>(
+ InvokeCallbackMethod<SupportChaining>(
mThisVal.get(), mResolveRejectMethod, MaybeMove(aValue),
std::move(mCompletionPromise));
@@ -822,18 +811,14 @@ class MozPromise : public MozPromiseBase {
class ThenValue<ResolveFunction, RejectFunction> : public ThenValueBase {
friend class ThenCommand<ThenValue>;
- using R1 = typename RemoveSmartPointer<
- typename detail::MethodTrait<ResolveFunction>::ReturnType>::Type;
- using R2 = typename RemoveSmartPointer<
- typename detail::MethodTrait<RejectFunction>::ReturnType>::Type;
- using SupportChaining =
- std::integral_constant<bool, IsMozPromise<R1>::value &&
- std::is_same_v<R1, R2>>;
+ using R1 = RemoveSmartPointer<MethodReturnType<ResolveFunction>>;
+ using R2 = RemoveSmartPointer<MethodReturnType<RejectFunction>>;
+ constexpr static bool SupportChaining =
+ IsMozPromise<R1> && std::is_same_v<R1, R2>;
// Fall back to MozPromise when promise chaining is not supported to make
// code compile.
- using PromiseType =
- std::conditional_t<SupportChaining::value, R1, MozPromise>;
+ using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>;
public:
ThenValue(nsISerialEventTarget* aResponseTarget,
@@ -867,11 +852,11 @@ class MozPromise : public MozPromiseBase {
// easily. We could fix this if need be, though it's quite easy to work
// around by just capturing something.
if (aValue.IsResolve()) {
- InvokeCallbackMethod<SupportChaining::value>(
+ InvokeCallbackMethod<SupportChaining>(
mResolveFunction.ptr(), &ResolveFunction::operator(),
MaybeMove(aValue.ResolveValue()), std::move(mCompletionPromise));
} else {
- InvokeCallbackMethod<SupportChaining::value>(
+ InvokeCallbackMethod<SupportChaining>(
mRejectFunction.ptr(), &RejectFunction::operator(),
MaybeMove(aValue.RejectValue()), std::move(mCompletionPromise));
}
@@ -896,15 +881,12 @@ class MozPromise : public MozPromiseBase {
class ThenValue<ResolveRejectFunction> : public ThenValueBase {
friend class ThenCommand<ThenValue>;
- using R1 = typename RemoveSmartPointer<
- typename detail::MethodTrait<ResolveRejectFunction>::ReturnType>::Type;
- using SupportChaining =
- std::integral_constant<bool, IsMozPromise<R1>::value>;
+ using R1 = RemoveSmartPointer<MethodReturnType<ResolveRejectFunction>>;
+ constexpr static bool SupportChaining = IsMozPromise<R1>;
// Fall back to MozPromise when promise chaining is not supported to make
// code compile.
- using PromiseType =
- std::conditional_t<SupportChaining::value, R1, MozPromise>;
+ using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>;
public:
ThenValue(nsISerialEventTarget* aResponseTarget,
@@ -935,7 +917,7 @@ class MozPromise : public MozPromiseBase {
// classes with ::operator()), since it allows us to share code more
// easily. We could fix this if need be, though it's quite easy to work
// around by just capturing something.
- InvokeCallbackMethod<SupportChaining::value>(
+ InvokeCallbackMethod<SupportChaining>(
mResolveRejectFunction.ptr(), &ResolveRejectFunction::operator(),
MaybeMove(aValue), std::move(mCompletionPromise));
@@ -998,7 +980,7 @@ class MozPromise : public MozPromiseBase {
MozPromise* aReceiver)
: mCallSite(aCallSite), mThenValue(aThenValue), mReceiver(aReceiver) {}
- ThenCommand(ThenCommand&& aOther) = default;
+ ThenCommand(ThenCommand&& aOther) noexcept = default;
public:
~ThenCommand() {
@@ -1013,7 +995,7 @@ class MozPromise : public MozPromiseBase {
// p->Then(thread2, ...);
operator RefPtr<PromiseType>() {
static_assert(
- ThenValueType::SupportChaining::value,
+ ThenValueType::SupportChaining,
"The resolve/reject callback needs to return a RefPtr<MozPromise> "
"in order to do promise chaining.");
@@ -1336,12 +1318,18 @@ class MozPromise<ResolveValueT, RejectValueT, IsExclusive>::Private
};
// A generic promise type that does the trick for simple use cases.
-typedef MozPromise<bool, nsresult, /* IsExclusive = */ true> GenericPromise;
+//
+// Vaguely deprecated: prefer explicitly naming the resolve- and reject-type.
+// Additionally, prefer `mozilla::Ok` as the resolve-type if the boolean's value
+// is irrelevant.
+using GenericPromise = MozPromise<bool, nsresult, /* IsExclusive = */ true>;
// A generic, non-exclusive promise type that does the trick for simple use
// cases.
-typedef MozPromise<bool, nsresult, /* IsExclusive = */ false>
- GenericNonExclusivePromise;
+//
+// Vaguely deprecated, as above.
+using GenericNonExclusivePromise =
+ MozPromise<bool, nsresult, /* IsExclusive = */ false>;
/*
* Class to encapsulate a promise for a particular role. Use this as the member
@@ -1352,8 +1340,9 @@ class MozPromiseHolderBase {
public:
MozPromiseHolderBase() = default;
- MozPromiseHolderBase(MozPromiseHolderBase&& aOther) = default;
- MozPromiseHolderBase& operator=(MozPromiseHolderBase&& aOther) = default;
+ MozPromiseHolderBase(MozPromiseHolderBase&& aOther) noexcept = default;
+ MozPromiseHolderBase& operator=(MozPromiseHolderBase&& aOther) noexcept =
+ default;
~MozPromiseHolderBase() { MOZ_ASSERT(!mPromise); }
@@ -1511,8 +1500,8 @@ class MozPromiseRequestHolder {
// will never be called.
void Disconnect() {
MOZ_ASSERT(Exists());
- mRequest->Disconnect();
- mRequest = nullptr;
+ RefPtr request = std::move(mRequest);
+ request->Disconnect();
}
void DisconnectIfExists() {
@@ -1700,30 +1689,26 @@ class ProxyFunctionRunnable : public CancelableRunnable {
UniquePtr<FunctionStorage> mFunction;
};
-// Note: The following struct and function are not for public consumption (yet?)
-// as we would prefer all calls to pass on-the-spot lambdas (or at least moved
-// function objects). They could be moved outside of detail if really needed.
+template <typename T>
+constexpr static bool IsRefPtrMozPromise = false;
+template <typename T, typename U, bool B>
+constexpr static bool IsRefPtrMozPromise<RefPtr<MozPromise<T, U, B>>> = true;
-// We prefer getting function objects by non-lvalue-ref (to avoid copying them
-// and their captures). This struct is a tag that allows the use of objects
-// through lvalue-refs where necessary.
-struct AllowInvokeAsyncFunctionLVRef {};
+} // namespace detail
-// Invoke a function object (e.g., lambda or std/mozilla::function)
-// asynchronously; note that the object will be copied if provided by
-// lvalue-ref. Return a promise that the function should eventually resolve or
-// reject.
+// Invoke a function object (e.g., lambda) asynchronously.
+// Return a promise that the function should eventually resolve or reject.
template <typename Function>
static auto InvokeAsync(nsISerialEventTarget* aTarget, const char* aCallerName,
- AllowInvokeAsyncFunctionLVRef, Function&& aFunction)
- -> decltype(aFunction()) {
- static_assert(
- IsRefcountedSmartPointer<decltype(aFunction())>::value &&
- IsMozPromise<
- typename RemoveSmartPointer<decltype(aFunction())>::Type>::value,
- "Function object must return RefPtr<MozPromise>");
+ Function&& aFunction) -> decltype(aFunction()) {
+ static_assert(!std::is_lvalue_reference_v<Function>,
+ "Function object must not be passed by lvalue-ref (to avoid "
+ "unplanned copies); Consider move()ing the object.");
+
+ static_assert(detail::IsRefPtrMozPromise<decltype(aFunction())>,
+ "Function object must return RefPtr<MozPromise>");
MOZ_ASSERT(aTarget);
- typedef typename RemoveSmartPointer<decltype(aFunction())>::Type PromiseType;
+ typedef RemoveSmartPointer<decltype(aFunction())> PromiseType;
typedef detail::ProxyFunctionRunnable<Function, PromiseType>
ProxyRunnableType;
@@ -1733,21 +1718,6 @@ static auto InvokeAsync(nsISerialEventTarget* aTarget, const char* aCallerName,
return p;
}
-} // namespace detail
-
-// Invoke a function object (e.g., lambda) asynchronously.
-// Return a promise that the function should eventually resolve or reject.
-template <typename Function>
-static auto InvokeAsync(nsISerialEventTarget* aTarget, const char* aCallerName,
- Function&& aFunction) -> decltype(aFunction()) {
- static_assert(!std::is_lvalue_reference_v<Function>,
- "Function object must not be passed by lvalue-ref (to avoid "
- "unplanned copies); Consider move()ing the object.");
- return detail::InvokeAsync(aTarget, aCallerName,
- detail::AllowInvokeAsyncFunctionLVRef(),
- std::forward<Function>(aFunction));
-}
-
# undef PROMISE_LOG
# undef PROMISE_ASSERT
# undef PROMISE_DEBUG