mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-24 19:37:15 +00:00
Bug 1575744 - P4. Add MozPromise::FromDomPromise. r=bholley
Similar to MozPromise::FromGeckoResult. Allows to create a MozPromise that will be resolved/rejected when the JS promise does the same. It would be nice to be able to chain the two promise types, but it would be an additional effort. MozPromise::FromDomPromise is limited to primitive types only and the reject value type must be nsresult. Differential Revision: https://phabricator.services.mozilla.com/D46017 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
89412cad70
commit
912b0df630
54
dom/promise/PromiseNativeHandler.cpp
Normal file
54
dom/promise/PromiseNativeHandler.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "PromiseNativeHandler.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS0(DomPromiseListener)
|
||||
|
||||
DomPromiseListener::DomPromiseListener(dom::Promise* aDOMPromise) {
|
||||
aDOMPromise->AppendNativeHandler(this);
|
||||
}
|
||||
|
||||
DomPromiseListener::DomPromiseListener(dom::Promise* aDOMPromise,
|
||||
CallbackType&& aResolve,
|
||||
CallbackType&& aReject)
|
||||
: mResolve(Some(std::move(aResolve))), mReject(Some(std::move(aReject))) {
|
||||
aDOMPromise->AppendNativeHandler(this);
|
||||
}
|
||||
|
||||
void DomPromiseListener::ResolvedCallback(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue) {
|
||||
if (mResolve) {
|
||||
(*mResolve)(aCx, aValue);
|
||||
}
|
||||
// Let's clear the lambdas in case we have a cycle to ourselves.
|
||||
mResolve.reset();
|
||||
mReject.reset();
|
||||
}
|
||||
|
||||
void DomPromiseListener::RejectedCallback(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue) {
|
||||
if (mReject) {
|
||||
(*mReject)(aCx, aValue);
|
||||
}
|
||||
// Let's clear the lambdas in case we have a cycle to ourselves.
|
||||
mResolve.reset();
|
||||
mReject.reset();
|
||||
}
|
||||
|
||||
void DomPromiseListener::SetResolvers(CallbackType&& aResolve,
|
||||
CallbackType&& aReject) {
|
||||
mResolve = Some(std::move(aResolve));
|
||||
mReject = Some(std::move(aReject));
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -7,12 +7,15 @@
|
||||
#ifndef mozilla_dom_PromiseNativeHandler_h
|
||||
#define mozilla_dom_PromiseNativeHandler_h
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include <functional>
|
||||
#include "js/TypeDecls.h"
|
||||
#include "nsISupports.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Promise;
|
||||
|
||||
/*
|
||||
* PromiseNativeHandler allows C++ to react to a Promise being
|
||||
* rejected/resolved. A PromiseNativeHandler can be appended to a Promise using
|
||||
@ -20,7 +23,7 @@ namespace dom {
|
||||
*/
|
||||
class PromiseNativeHandler : public nsISupports {
|
||||
protected:
|
||||
virtual ~PromiseNativeHandler() {}
|
||||
virtual ~PromiseNativeHandler() = default;
|
||||
|
||||
public:
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
@ -32,6 +35,27 @@ class PromiseNativeHandler : public nsISupports {
|
||||
JS::Handle<JS::Value> aValue) = 0;
|
||||
};
|
||||
|
||||
// This class is used to set C++ callbacks once a dom Promise a resolved or
|
||||
// rejected.
|
||||
class DomPromiseListener final : public PromiseNativeHandler {
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
public:
|
||||
using CallbackType = std::function<void(JSContext*, JS::Handle<JS::Value>)>;
|
||||
|
||||
explicit DomPromiseListener(Promise* aDOMPromise);
|
||||
DomPromiseListener(Promise* aDOMPromise, CallbackType&& aResolve,
|
||||
CallbackType&& aReject);
|
||||
void SetResolvers(CallbackType&& aResolve, CallbackType&& aReject);
|
||||
void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
|
||||
void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
|
||||
|
||||
private:
|
||||
~DomPromiseListener() = default;
|
||||
Maybe<CallbackType> mResolve;
|
||||
Maybe<CallbackType> mReject;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -18,6 +18,7 @@ EXPORTS.mozilla.dom += [
|
||||
UNIFIED_SOURCES += [
|
||||
'Promise.cpp',
|
||||
'PromiseDebugging.cpp',
|
||||
'PromiseNativeHandler.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
|
@ -10,9 +10,10 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "DocumentChannelParent.h"
|
||||
#include "mozilla/dom/nsCSPContext.h"
|
||||
#include "mozilla/MozPromiseInlines.h" // For MozPromise::FromDomPromise
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/dom/nsCSPContext.h"
|
||||
|
||||
#include "nsHttp.h"
|
||||
#include "nsHttpChannel.h"
|
||||
@ -124,7 +125,6 @@
|
||||
#include "../../cache2/CacheFileUtils.h"
|
||||
#include "../../cache2/CacheHashUtils.h"
|
||||
#include "nsINetworkLinkService.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/ServiceWorkerUtils.h"
|
||||
#include "mozilla/net/AsyncUrlChannelClassifier.h"
|
||||
@ -7241,51 +7241,6 @@ nsHttpChannel::GetRequestMethod(nsACString& aMethod) {
|
||||
return HttpBaseChannel::GetRequestMethod(aMethod);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpChannel::nsIRequestObserver
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// This class is used to convert from a DOM promise to a MozPromise.
|
||||
class DomPromiseListener final : dom::PromiseNativeHandler {
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
static RefPtr<nsHttpChannel::ContentProcessIdPromise> Create(
|
||||
dom::Promise* aDOMPromise) {
|
||||
MOZ_ASSERT(aDOMPromise);
|
||||
RefPtr<DomPromiseListener> handler = new DomPromiseListener();
|
||||
RefPtr<nsHttpChannel::ContentProcessIdPromise> promise =
|
||||
handler->mPromiseHolder.Ensure(__func__);
|
||||
aDOMPromise->AppendNativeHandler(handler);
|
||||
return promise;
|
||||
}
|
||||
|
||||
virtual void ResolvedCallback(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue) override {
|
||||
uint64_t cpId;
|
||||
if (!JS::ToUint64(aCx, aValue, &cpId)) {
|
||||
mPromiseHolder.Reject(NS_ERROR_FAILURE, __func__);
|
||||
return;
|
||||
}
|
||||
mPromiseHolder.Resolve(cpId, __func__);
|
||||
}
|
||||
|
||||
virtual void RejectedCallback(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue) override {
|
||||
if (!aValue.isInt32()) {
|
||||
mPromiseHolder.Reject(NS_ERROR_DOM_NOT_NUMBER_ERR, __func__);
|
||||
return;
|
||||
}
|
||||
mPromiseHolder.Reject((nsresult)aValue.toInt32(), __func__);
|
||||
}
|
||||
|
||||
private:
|
||||
DomPromiseListener() = default;
|
||||
~DomPromiseListener() = default;
|
||||
MozPromiseHolder<nsHttpChannel::ContentProcessIdPromise> mPromiseHolder;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS0(DomPromiseListener)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpChannel::nsIProcessSwitchRequestor
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -7315,7 +7270,7 @@ NS_IMETHODIMP nsHttpChannel::SwitchProcessTo(
|
||||
}
|
||||
|
||||
mRedirectContentProcessIdPromise =
|
||||
DomPromiseListener::Create(aContentProcessIdPromise);
|
||||
ContentProcessIdPromise::FromDomPromise(aContentProcessIdPromise);
|
||||
mCrossProcessRedirectIdentifier = aIdentifier;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -7618,6 +7573,10 @@ nsresult nsHttpChannel::ProcessCrossOriginResourcePolicyHeader() {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpChannel::nsIRequestObserver
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::OnStartRequest(nsIRequest* request) {
|
||||
nsresult rv;
|
||||
|
@ -9,8 +9,8 @@
|
||||
|
||||
# include "mozilla/Logging.h"
|
||||
# include "mozilla/Maybe.h"
|
||||
# include "mozilla/Mutex.h"
|
||||
# include "mozilla/Monitor.h"
|
||||
# include "mozilla/Mutex.h"
|
||||
# include "mozilla/RefPtr.h"
|
||||
# include "mozilla/Tuple.h"
|
||||
# include "mozilla/TypeTraits.h"
|
||||
@ -38,6 +38,10 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class Promise;
|
||||
}
|
||||
|
||||
extern LazyLogModule gMozPromiseLog;
|
||||
|
||||
# define PROMISE_LOG(x, ...) \
|
||||
@ -954,6 +958,12 @@ class MozPromise : public MozPromiseBase {
|
||||
}
|
||||
# endif
|
||||
|
||||
// Creates a C++ MozPromise from its JS counterpart, dom::Promise.
|
||||
// FromDomPromise currently only supports primitive types (int8/16/32, float,
|
||||
// double) And the reject value type must be a nsresult.
|
||||
// To use, please include MozPromiseInlines.h
|
||||
static RefPtr<MozPromise> FromDomPromise(dom::Promise* aDOMPromise);
|
||||
|
||||
// Note we expose the function AssertIsDead() instead of IsDead() since
|
||||
// checking IsDead() is a data race in the situation where the request is not
|
||||
// dead. Therefore we enforce the form |Assert(IsDead())| by exposing
|
||||
|
53
xpcom/threads/MozPromiseInlines.h
Normal file
53
xpcom/threads/MozPromiseInlines.h
Normal file
@ -0,0 +1,53 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if !defined(MozPromiseInlines_h_)
|
||||
# define MozPromiseInlines_h_
|
||||
|
||||
# include "mozilla/MozPromise.h"
|
||||
# include "mozilla/dom/PrimitiveConversions.h"
|
||||
# include "mozilla/dom/PromiseNativeHandler.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Creates a C++ MozPromise from its JS counterpart, dom::Promise.
|
||||
// FromDomPromise currently only supports primitive types (int8/16/32, float,
|
||||
// double) And the reject value type must be a nsresult.
|
||||
template <typename ResolveValueT, typename RejectValueT, bool IsExclusive>
|
||||
RefPtr<MozPromise<ResolveValueT, RejectValueT, IsExclusive>>
|
||||
MozPromise<ResolveValueT, RejectValueT, IsExclusive>::FromDomPromise(
|
||||
dom::Promise* aDOMPromise) {
|
||||
static_assert(IsSame<RejectValueType, nsresult>::value,
|
||||
"Reject type must be nsresult");
|
||||
RefPtr<Private> p = new Private(__func__);
|
||||
RefPtr<dom::DomPromiseListener> listener = new dom::DomPromiseListener(
|
||||
aDOMPromise,
|
||||
[p](JSContext* aCx, JS::Handle<JS::Value> aValue) {
|
||||
ResolveValueT value;
|
||||
bool ok = dom::ValueToPrimitive<ResolveValueT,
|
||||
dom::ConversionBehavior::eDefault>(
|
||||
aCx, aValue, &value);
|
||||
if (!ok) {
|
||||
p->Reject(NS_ERROR_FAILURE, __func__);
|
||||
return;
|
||||
}
|
||||
p->Resolve(value, __func__);
|
||||
},
|
||||
[p](JSContext* aCx, JS::Handle<JS::Value> aValue) {
|
||||
if (!aValue.isInt32()) {
|
||||
p->Reject(NS_ERROR_DOM_NOT_NUMBER_ERR, __func__);
|
||||
return;
|
||||
}
|
||||
nsresult rv = nsresult(aValue.toInt32());
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
p->Reject(rv, __func__);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -53,6 +53,7 @@ EXPORTS.mozilla += [
|
||||
'MainThreadIdlePeriod.h',
|
||||
'Monitor.h',
|
||||
'MozPromise.h',
|
||||
'MozPromiseInlines.h',
|
||||
'Mutex.h',
|
||||
'PerformanceCounter.h',
|
||||
'Queue.h',
|
||||
|
Loading…
x
Reference in New Issue
Block a user