#ifndef vm_AsyncIteration_h
#define vm_AsyncIteration_h
#include "builtin/Promise.h"
#include "js/Class.h"
#include "vm/GeneratorObject.h"
#include "vm/JSContext.h"
#include "vm/JSObject.h"
#include "vm/List.h"
namespace js {
class AsyncGeneratorObject;
MOZ_MUST_USE bool AsyncGeneratorAwaitedFulfilled(
JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue value);
MOZ_MUST_USE bool AsyncGeneratorAwaitedRejected(
JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue reason);
MOZ_MUST_USE bool AsyncGeneratorYieldReturnAwaitedFulfilled(
JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue value);
MOZ_MUST_USE bool AsyncGeneratorYieldReturnAwaitedRejected(
JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue reason);
class AsyncGeneratorRequest : public NativeObject {
private:
enum AsyncGeneratorRequestSlots {
Slot_CompletionKind = 0,
Slot_CompletionValue,
Slot_Promise,
Slots,
};
void init(CompletionKind completionKind, const Value& completionValue,
PromiseObject* promise) {
setFixedSlot(Slot_CompletionKind,
Int32Value(static_cast<int32_t>(completionKind)));
setFixedSlot(Slot_CompletionValue, completionValue);
setFixedSlot(Slot_Promise, ObjectValue(*promise));
}
void clearData() {
setFixedSlot(Slot_CompletionValue, NullValue());
setFixedSlot(Slot_Promise, NullValue());
}
friend AsyncGeneratorObject;
public:
static const Class class_;
static AsyncGeneratorRequest* create(JSContext* cx,
CompletionKind completionKind,
HandleValue completionValue,
Handle<PromiseObject*> promise);
CompletionKind completionKind() const {
return static_cast<CompletionKind>(
getFixedSlot(Slot_CompletionKind).toInt32());
}
JS::Value completionValue() const {
return getFixedSlot(Slot_CompletionValue);
}
PromiseObject* promise() const {
return &getFixedSlot(Slot_Promise).toObject().as<PromiseObject>();
}
};
class AsyncGeneratorObject : public AbstractGeneratorObject {
private:
enum AsyncGeneratorObjectSlots {
Slot_State = AbstractGeneratorObject::RESERVED_SLOTS,
Slot_QueueOrRequest,
Slot_CachedRequest,
Slots
};
enum State {
State_SuspendedStart,
State_SuspendedYield,
State_Executing,
State_AwaitingYieldReturn,
State_AwaitingReturn,
State_Completed
};
State state() const {
return static_cast<State>(getFixedSlot(Slot_State).toInt32());
}
void setState(State state_) { setFixedSlot(Slot_State, Int32Value(state_)); }
bool isSingleQueue() const {
return getFixedSlot(Slot_QueueOrRequest).isNull() ||
getFixedSlot(Slot_QueueOrRequest)
.toObject()
.is<AsyncGeneratorRequest>();
}
bool isSingleQueueEmpty() const {
return getFixedSlot(Slot_QueueOrRequest).isNull();
}
void setSingleQueueRequest(AsyncGeneratorRequest* request) {
setFixedSlot(Slot_QueueOrRequest, ObjectValue(*request));
}
void clearSingleQueueRequest() {
setFixedSlot(Slot_QueueOrRequest, NullValue());
}
AsyncGeneratorRequest* singleQueueRequest() const {
return &getFixedSlot(Slot_QueueOrRequest)
.toObject()
.as<AsyncGeneratorRequest>();
}
ListObject* queue() const {
return &getFixedSlot(Slot_QueueOrRequest).toObject().as<ListObject>();
}
void setQueue(ListObject* queue_) {
setFixedSlot(Slot_QueueOrRequest, ObjectValue(*queue_));
}
public:
static const Class class_;
static AsyncGeneratorObject* create(JSContext* cx, HandleFunction asyncGen);
bool isSuspendedStart() const { return state() == State_SuspendedStart; }
bool isSuspendedYield() const { return state() == State_SuspendedYield; }
bool isExecuting() const { return state() == State_Executing; }
bool isAwaitingYieldReturn() const {
return state() == State_AwaitingYieldReturn;
}
bool isAwaitingReturn() const { return state() == State_AwaitingReturn; }
bool isCompleted() const { return state() == State_Completed; }
void setSuspendedStart() { setState(State_SuspendedStart); }
void setSuspendedYield() { setState(State_SuspendedYield); }
void setExecuting() { setState(State_Executing); }
void setAwaitingYieldReturn() { setState(State_AwaitingYieldReturn); }
void setAwaitingReturn() { setState(State_AwaitingReturn); }
void setCompleted() { setState(State_Completed); }
static MOZ_MUST_USE bool enqueueRequest(
JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
Handle<AsyncGeneratorRequest*> request);
static AsyncGeneratorRequest* dequeueRequest(
JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
static AsyncGeneratorRequest* peekRequest(
Handle<AsyncGeneratorObject*> asyncGenObj);
bool isQueueEmpty() const {
if (isSingleQueue()) {
return isSingleQueueEmpty();
}
return queue()->getDenseInitializedLength() == 0;
}
static AsyncGeneratorRequest* createRequest(
JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
CompletionKind completionKind, HandleValue completionValue,
Handle<PromiseObject*> promise);
void cacheRequest(AsyncGeneratorRequest* request) {
if (hasCachedRequest()) {
return;
}
request->clearData();
setFixedSlot(Slot_CachedRequest, ObjectValue(*request));
}
private:
bool hasCachedRequest() const {
return getFixedSlot(Slot_CachedRequest).isObject();
}
AsyncGeneratorRequest* takeCachedRequest() {
auto request = &getFixedSlot(Slot_CachedRequest)
.toObject()
.as<AsyncGeneratorRequest>();
clearCachedRequest();
return request;
}
void clearCachedRequest() { setFixedSlot(Slot_CachedRequest, NullValue()); }
};
JSObject* CreateAsyncFromSyncIterator(JSContext* cx, HandleObject iter,
HandleValue nextMethod);
class AsyncFromSyncIteratorObject : public NativeObject {
private:
enum AsyncFromSyncIteratorObjectSlots {
Slot_Iterator = 0,
Slot_NextMethod = 1,
Slots
};
void init(JSObject* iterator, const Value& nextMethod) {
setFixedSlot(Slot_Iterator, ObjectValue(*iterator));
setFixedSlot(Slot_NextMethod, nextMethod);
}
public:
static const Class class_;
static JSObject* create(JSContext* cx, HandleObject iter,
HandleValue nextMethod);
JSObject* iterator() const { return &getFixedSlot(Slot_Iterator).toObject(); }
const Value& nextMethod() const { return getFixedSlot(Slot_NextMethod); }
};
MOZ_MUST_USE bool AsyncGeneratorResume(
JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
CompletionKind completionKind, HandleValue argument);
}
#endif