promise.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Copyright (c) 2018 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #ifndef ELECTRON_SHELL_COMMON_GIN_HELPER_PROMISE_H_
  5. #define ELECTRON_SHELL_COMMON_GIN_HELPER_PROMISE_H_
  6. #include <string>
  7. #include <string_view>
  8. #include <tuple>
  9. #include <type_traits>
  10. #include <utility>
  11. #include "base/memory/raw_ptr.h"
  12. #include "base/memory/scoped_refptr.h"
  13. #include "base/task/task_runner.h"
  14. #include "shell/common/gin_converters/std_converter.h"
  15. #include "shell/common/gin_helper/microtasks_scope.h"
  16. #include "v8/include/v8-context.h"
  17. namespace gin_helper {
  18. // A wrapper around the v8::Promise.
  19. //
  20. // This is the non-template base class to share code between templates
  21. // instances.
  22. //
  23. // This is a move-only type that should always be `std::move`d when passed to
  24. // callbacks, and it should be destroyed on the same thread of creation.
  25. class PromiseBase {
  26. public:
  27. explicit PromiseBase(v8::Isolate* isolate);
  28. PromiseBase(v8::Isolate* isolate, v8::Local<v8::Promise::Resolver> handle);
  29. PromiseBase();
  30. ~PromiseBase();
  31. // disable copy
  32. PromiseBase(const PromiseBase&) = delete;
  33. PromiseBase& operator=(const PromiseBase&) = delete;
  34. // Support moving.
  35. PromiseBase(PromiseBase&&);
  36. PromiseBase& operator=(PromiseBase&&);
  37. // Helper for rejecting promise with error message.
  38. static void RejectPromise(PromiseBase&& promise, std::string_view errmsg);
  39. v8::Maybe<bool> Reject();
  40. v8::Maybe<bool> Reject(v8::Local<v8::Value> except);
  41. v8::Maybe<bool> RejectWithErrorMessage(std::string_view message);
  42. v8::Local<v8::Context> GetContext() const;
  43. v8::Local<v8::Promise> GetHandle() const;
  44. v8::Isolate* isolate() const { return isolate_; }
  45. protected:
  46. struct SettleScope {
  47. explicit SettleScope(const PromiseBase& base);
  48. ~SettleScope();
  49. v8::HandleScope handle_scope_;
  50. v8::Local<v8::Context> context_;
  51. gin_helper::MicrotasksScope microtasks_scope_;
  52. v8::Context::Scope context_scope_;
  53. };
  54. v8::Local<v8::Promise::Resolver> GetInner() const;
  55. static scoped_refptr<base::TaskRunner> GetTaskRunner();
  56. private:
  57. raw_ptr<v8::Isolate> isolate_;
  58. v8::Global<v8::Context> context_;
  59. v8::Global<v8::Promise::Resolver> resolver_;
  60. };
  61. // Template implementation that returns values.
  62. template <typename RT>
  63. class Promise : public PromiseBase {
  64. public:
  65. using PromiseBase::PromiseBase;
  66. // Helper for resolving the promise with |result|.
  67. static void ResolvePromise(Promise<RT> promise, RT result) {
  68. if (auto task_runner = GetTaskRunner()) {
  69. task_runner->PostTask(
  70. FROM_HERE, base::BindOnce([](Promise<RT> promise,
  71. RT result) { promise.Resolve(result); },
  72. std::move(promise), std::move(result)));
  73. } else {
  74. promise.Resolve(result);
  75. }
  76. }
  77. // Returns an already-resolved promise.
  78. static v8::Local<v8::Promise> ResolvedPromise(v8::Isolate* isolate,
  79. RT result) {
  80. Promise<RT> resolved(isolate);
  81. resolved.Resolve(result);
  82. return resolved.GetHandle();
  83. }
  84. // Convert to another type.
  85. template <typename NT>
  86. Promise<NT> As() {
  87. return Promise<NT>{isolate(), GetInner()};
  88. }
  89. v8::Maybe<bool> Resolve(const RT& value) {
  90. SettleScope settle_scope{*this};
  91. return GetInner()->Resolve(settle_scope.context_,
  92. gin::ConvertToV8(isolate(), value));
  93. }
  94. template <typename... ResolveType>
  95. v8::MaybeLocal<v8::Promise> Then(
  96. base::OnceCallback<void(ResolveType...)> cb) {
  97. static_assert(sizeof...(ResolveType) <= 1,
  98. "A promise's 'Then' callback should only receive at most one "
  99. "parameter");
  100. static_assert(
  101. std::is_same<RT, std::tuple_element_t<0, std::tuple<ResolveType...>>>(),
  102. "A promises's 'Then' callback must handle the same type as the "
  103. "promises resolve type");
  104. SettleScope settle_scope{*this};
  105. v8::Local<v8::Value> value = gin::ConvertToV8(isolate(), std::move(cb));
  106. v8::Local<v8::Function> handler = value.As<v8::Function>();
  107. return GetHandle()->Then(settle_scope.context_, handler);
  108. }
  109. };
  110. // Template implementation that returns nothing.
  111. template <>
  112. class Promise<void> : public PromiseBase {
  113. public:
  114. using PromiseBase::PromiseBase;
  115. // Helper for resolving the empty promise.
  116. static void ResolvePromise(Promise<void> promise);
  117. // Returns an already-resolved promise.
  118. static v8::Local<v8::Promise> ResolvedPromise(v8::Isolate* isolate);
  119. v8::Maybe<bool> Resolve();
  120. };
  121. } // namespace gin_helper
  122. namespace gin {
  123. template <typename T>
  124. struct Converter<gin_helper::Promise<T>> {
  125. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  126. const gin_helper::Promise<T>& val) {
  127. return val.GetHandle();
  128. }
  129. // TODO(MarshallOfSound): Implement FromV8 to allow promise chaining
  130. // in native land
  131. // static bool FromV8(v8::Isolate* isolate,
  132. // v8::Local<v8::Value> val,
  133. // Promise* out);
  134. };
  135. } // namespace gin
  136. #endif // ELECTRON_SHELL_COMMON_GIN_HELPER_PROMISE_H_