Bug 856410 - Implement futures - Part 3: resolver.resolve(new Future(). r=mounir

This commit is contained in:
Andrea Marchesini 2013-06-11 21:41:22 -04:00
parent 0cbca2866e
commit 32512bb765
4 changed files with 101 additions and 6 deletions

View File

@ -70,7 +70,7 @@ ResolveFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
ac.construct(cx, rooted);
}
mResolver->Resolve(cx, aValue, FutureResolver::SyncTask);
mResolver->ResolveInternal(cx, aValue, FutureResolver::SyncTask);
}
// RejectFutureCallback
@ -109,7 +109,7 @@ RejectFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
ac.construct(cx, rooted);
}
mResolver->Reject(cx, aValue, FutureResolver::SyncTask);
mResolver->RejectInternal(cx, aValue, FutureResolver::SyncTask);
}
// WrapperFutureCallback
@ -162,13 +162,13 @@ WrapperFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
if (rv.Failed() && rv.IsJSException()) {
Optional<JS::Handle<JS::Value> > value(cx);
rv.StealJSException(cx, &value.Value());
mNextResolver->Reject(cx, value, FutureResolver::SyncTask);
mNextResolver->RejectInternal(cx, value, FutureResolver::SyncTask);
return;
}
// Otherwise, run resolver's resolve with value and the synchronous flag
// set.
mNextResolver->Resolve(cx, value, FutureResolver::SyncTask);
mNextResolver->ResolveInternal(cx, value, FutureResolver::SyncTask);
}
// SimpleWrapperFutureCallback

View File

@ -7,6 +7,7 @@
#include "mozilla/dom/FutureResolver.h"
#include "mozilla/dom/FutureBinding.h"
#include "mozilla/dom/Future.h"
#include "FutureCallback.h"
namespace mozilla {
namespace dom {
@ -88,10 +89,30 @@ FutureResolver::Resolve(JSContext* aCx,
return;
}
// TODO: if the arg is a future?
ResolveInternal(aCx, aValue, aAsynchronous);
}
void
FutureResolver::ResolveInternal(JSContext* aCx,
const Optional<JS::Handle<JS::Value> >& aValue,
FutureTaskSync aAsynchronous)
{
mResolvePending = true;
// TODO: Bug 879245 - Then-able objects
if (aValue.WasPassed() && aValue.Value().isObject()) {
JS::Rooted<JSObject*> valueObj(aCx, &aValue.Value().toObject());
Future* nextFuture;
nsresult rv = UnwrapObject<Future>(aCx, valueObj, nextFuture);
if (NS_SUCCEEDED(rv)) {
nsRefPtr<FutureCallback> resolveCb = new ResolveFutureCallback(this);
nsRefPtr<FutureCallback> rejectCb = new RejectFutureCallback(this);
nextFuture->AppendCallbacks(resolveCb, rejectCb);
return;
}
}
// If the synchronous flag is set, process future's resolve callbacks with
// value. Otherwise, the synchronous flag is unset, queue a task to process
// future's resolve callbacks with value. Otherwise, the synchronous flag is
@ -109,6 +130,14 @@ FutureResolver::Reject(JSContext* aCx,
return;
}
RejectInternal(aCx, aValue, aAsynchronous);
}
void
FutureResolver::RejectInternal(JSContext* aCx,
const Optional<JS::Handle<JS::Value> >& aValue,
FutureTaskSync aAsynchronous)
{
mResolvePending = true;
// If the synchronous flag is set, process future's reject callbacks with

View File

@ -53,6 +53,14 @@ public:
FutureTaskSync aSync = AsyncTask);
private:
void ResolveInternal(JSContext* aCx,
const Optional<JS::Handle<JS::Value> >& aValue,
FutureTaskSync aSync = AsyncTask);
void RejectInternal(JSContext* aCx,
const Optional<JS::Handle<JS::Value> >& aValue,
FutureTaskSync aSync = AsyncTask);
void RunTask(JS::Handle<JS::Value> aValue,
Future::FutureState aState, FutureTaskSync aSync);

View File

@ -287,6 +287,62 @@ function futureThenCatchOrderingReject() {
});
}
function futureNestedFuture() {
new Future(function(resolver) {
resolver.resolve(new Future(function(r) {
ok(true, "Nested future is executed");
r.resolve(42);
}));
}).then(function(value) {
is(value, 42, "Nested future is executed and then == 42");
runTest();
});
}
function futureNestedNestedFuture() {
new Future(function(resolver) {
resolver.resolve(new Future(function(r) {
ok(true, "Nested future is executed");
r.resolve(42);
}).then(function(what) { return what+1; }));
}).then(function(value) {
is(value, 43, "Nested future is executed and then == 43");
runTest();
});
}
function futureWrongNestedFuture() {
new Future(function(resolver) {
resolver.resolve(new Future(function(r) {
ok(true, "Nested future is executed");
r.resolve(42);
}));
resolver.reject(42);
}).then(function(value) {
is(value, 42, "Nested future is executed and then == 42");
runTest();
}, function(value) {
ok(false, "This is wrong");
});
}
function futureLoop() {
new Future(function(resolver) {
resolver.resolve(new Future(function(r) {
ok(true, "Nested future is executed");
r.resolve(new Future(function(r) {
ok(true, "Nested nested future is executed");
r.resolve(42);
}));
}));
}).then(function(value) {
is(value, 42, "Nested nested future is executed and then == 42");
runTest();
}, function(value) {
ok(false, "This is wrong");
});
}
var tests = [ futureResolve, futureReject,
futureException, futureGC, futureAsync,
futureDoubleDone, futureDoneException,
@ -294,7 +350,9 @@ var tests = [ futureResolve, futureReject,
futureRejectThenCatchDone2,
futureRejectThenCatchExceptionDone,
futureThenCatchOrderingResolve,
futureThenCatchOrderingReject
futureThenCatchOrderingReject,
futureNestedFuture, futureNestedNestedFuture,
futureWrongNestedFuture, futureLoop
];
function runTest() {