1// Copyright 2021 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef INCLUDE_V8_PROMISE_H_
6#define INCLUDE_V8_PROMISE_H_
7
8#include "v8-local-handle.h"  // NOLINT(build/include_directory)
9#include "v8-object.h"        // NOLINT(build/include_directory)
10#include "v8config.h"         // NOLINT(build/include_directory)
11
12namespace v8 {
13
14class Context;
15
16#ifndef V8_PROMISE_INTERNAL_FIELD_COUNT
17// The number of required internal fields can be defined by embedder.
18#define V8_PROMISE_INTERNAL_FIELD_COUNT 0
19#endif
20
21/**
22 * An instance of the built-in Promise constructor (ES6 draft).
23 */
24class V8_EXPORT Promise : public Object {
25 public:
26  /**
27   * State of the promise. Each value corresponds to one of the possible values
28   * of the [[PromiseState]] field.
29   */
30  enum PromiseState { kPending, kFulfilled, kRejected };
31
32  class V8_EXPORT Resolver : public Object {
33   public:
34    /**
35     * Create a new resolver, along with an associated promise in pending state.
36     */
37    static V8_WARN_UNUSED_RESULT MaybeLocal<Resolver> New(
38        Local<Context> context);
39
40    /**
41     * Extract the associated promise.
42     */
43    Local<Promise> GetPromise();
44
45    /**
46     * Resolve/reject the associated promise with a given value.
47     * Ignored if the promise is no longer pending.
48     */
49    V8_WARN_UNUSED_RESULT Maybe<bool> Resolve(Local<Context> context,
50                                              Local<Value> value);
51
52    V8_WARN_UNUSED_RESULT Maybe<bool> Reject(Local<Context> context,
53                                             Local<Value> value);
54
55    V8_INLINE static Resolver* Cast(Value* value) {
56#ifdef V8_ENABLE_CHECKS
57      CheckCast(value);
58#endif
59      return static_cast<Promise::Resolver*>(value);
60    }
61
62   private:
63    Resolver();
64    static void CheckCast(Value* obj);
65  };
66
67  /**
68   * Register a resolution/rejection handler with a promise.
69   * The handler is given the respective resolution/rejection value as
70   * an argument. If the promise is already resolved/rejected, the handler is
71   * invoked at the end of turn.
72   */
73  V8_WARN_UNUSED_RESULT MaybeLocal<Promise> Catch(Local<Context> context,
74                                                  Local<Function> handler);
75
76  V8_WARN_UNUSED_RESULT MaybeLocal<Promise> Then(Local<Context> context,
77                                                 Local<Function> handler);
78
79  V8_WARN_UNUSED_RESULT MaybeLocal<Promise> Then(Local<Context> context,
80                                                 Local<Function> on_fulfilled,
81                                                 Local<Function> on_rejected);
82
83  /**
84   * Returns true if the promise has at least one derived promise, and
85   * therefore resolve/reject handlers (including default handler).
86   */
87  bool HasHandler() const;
88
89  /**
90   * Returns the content of the [[PromiseResult]] field. The Promise must not
91   * be pending.
92   */
93  Local<Value> Result();
94
95  /**
96   * Returns the value of the [[PromiseState]] field.
97   */
98  PromiseState State();
99
100  /**
101   * Marks this promise as handled to avoid reporting unhandled rejections.
102   */
103  void MarkAsHandled();
104
105  /**
106   * Marks this promise as silent to prevent pausing the debugger when the
107   * promise is rejected.
108   */
109  void MarkAsSilent();
110
111  V8_INLINE static Promise* Cast(Value* value) {
112#ifdef V8_ENABLE_CHECKS
113    CheckCast(value);
114#endif
115    return static_cast<Promise*>(value);
116  }
117
118  static const int kEmbedderFieldCount = V8_PROMISE_INTERNAL_FIELD_COUNT;
119
120 private:
121  Promise();
122  static void CheckCast(Value* obj);
123};
124
125/**
126 * PromiseHook with type kInit is called when a new promise is
127 * created. When a new promise is created as part of the chain in the
128 * case of Promise.then or in the intermediate promises created by
129 * Promise.{race, all}/AsyncFunctionAwait, we pass the parent promise
130 * otherwise we pass undefined.
131 *
132 * PromiseHook with type kResolve is called at the beginning of
133 * resolve or reject function defined by CreateResolvingFunctions.
134 *
135 * PromiseHook with type kBefore is called at the beginning of the
136 * PromiseReactionJob.
137 *
138 * PromiseHook with type kAfter is called right at the end of the
139 * PromiseReactionJob.
140 */
141enum class PromiseHookType { kInit, kResolve, kBefore, kAfter };
142
143using PromiseHook = void (*)(PromiseHookType type, Local<Promise> promise,
144                             Local<Value> parent);
145
146// --- Promise Reject Callback ---
147enum PromiseRejectEvent {
148  kPromiseRejectWithNoHandler = 0,
149  kPromiseHandlerAddedAfterReject = 1,
150  kPromiseRejectAfterResolved = 2,
151  kPromiseResolveAfterResolved = 3,
152};
153
154class PromiseRejectMessage {
155 public:
156  PromiseRejectMessage(Local<Promise> promise, PromiseRejectEvent event,
157                       Local<Value> value)
158      : promise_(promise), event_(event), value_(value) {}
159
160  V8_INLINE Local<Promise> GetPromise() const { return promise_; }
161  V8_INLINE PromiseRejectEvent GetEvent() const { return event_; }
162  V8_INLINE Local<Value> GetValue() const { return value_; }
163
164 private:
165  Local<Promise> promise_;
166  PromiseRejectEvent event_;
167  Local<Value> value_;
168};
169
170using PromiseRejectCallback = void (*)(PromiseRejectMessage message);
171
172}  // namespace v8
173
174#endif  // INCLUDE_V8_PROMISE_H_
175