diff options
Diffstat (limited to 'xpcom/threads/MozPromise.h')
-rw-r--r-- | xpcom/threads/MozPromise.h | 200 |
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 |