dictionary.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // Copyright (c) 2019 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 SHELL_COMMON_GIN_HELPER_DICTIONARY_H_
  5. #define SHELL_COMMON_GIN_HELPER_DICTIONARY_H_
  6. #include <type_traits>
  7. #include <utility>
  8. #include "gin/dictionary.h"
  9. #include "shell/common/gin_converters/std_converter.h"
  10. #include "shell/common/gin_helper/accessor.h"
  11. #include "shell/common/gin_helper/function_template.h"
  12. #include "third_party/abseil-cpp/absl/types/optional.h"
  13. namespace gin_helper {
  14. // Adds a few more extends methods to gin::Dictionary.
  15. //
  16. // Note that as the destructor of gin::Dictionary is not virtual, and we want to
  17. // convert between 2 types, we must not add any member.
  18. class Dictionary : public gin::Dictionary {
  19. public:
  20. Dictionary() : gin::Dictionary(nullptr) {}
  21. Dictionary(v8::Isolate* isolate, v8::Local<v8::Object> object)
  22. : gin::Dictionary(isolate, object) {}
  23. // Allow implicitly converting from gin::Dictionary, as it is absolutely
  24. // safe in this case.
  25. Dictionary(const gin::Dictionary& dict) // NOLINT(runtime/explicit)
  26. : gin::Dictionary(dict) {}
  27. // Differences from the Get method in gin::Dictionary:
  28. // 1. This is a const method;
  29. // 2. It checks whether the key exists before reading;
  30. // 3. It accepts arbitrary type of key.
  31. template <typename K, typename V>
  32. bool Get(const K& key, V* out) const {
  33. // Check for existence before getting, otherwise this method will always
  34. // returns true when T == v8::Local<v8::Value>.
  35. v8::Local<v8::Context> context = isolate()->GetCurrentContext();
  36. v8::Local<v8::Value> v8_key = gin::ConvertToV8(isolate(), key);
  37. v8::Local<v8::Value> value;
  38. v8::Maybe<bool> result = GetHandle()->Has(context, v8_key);
  39. if (result.IsJust() && result.FromJust() &&
  40. GetHandle()->Get(context, v8_key).ToLocal(&value))
  41. return gin::ConvertFromV8(isolate(), value, out);
  42. return false;
  43. }
  44. // Differences from the Set method in gin::Dictionary:
  45. // 1. It accepts arbitrary type of key.
  46. template <typename K, typename V>
  47. bool Set(const K& key, const V& val) {
  48. v8::Local<v8::Value> v8_value;
  49. if (!gin::TryConvertToV8(isolate(), val, &v8_value))
  50. return false;
  51. v8::Maybe<bool> result =
  52. GetHandle()->Set(isolate()->GetCurrentContext(),
  53. gin::ConvertToV8(isolate(), key), v8_value);
  54. return !result.IsNothing() && result.FromJust();
  55. }
  56. // Like normal Get but put result in an absl::optional.
  57. template <typename T>
  58. bool GetOptional(base::StringPiece key, absl::optional<T>* out) const {
  59. T ret;
  60. if (Get(key, &ret)) {
  61. out->emplace(std::move(ret));
  62. return true;
  63. } else {
  64. return false;
  65. }
  66. }
  67. template <typename T>
  68. bool GetHidden(base::StringPiece key, T* out) const {
  69. v8::Local<v8::Context> context = isolate()->GetCurrentContext();
  70. v8::Local<v8::Private> privateKey =
  71. v8::Private::ForApi(isolate(), gin::StringToV8(isolate(), key));
  72. v8::Local<v8::Value> value;
  73. v8::Maybe<bool> result = GetHandle()->HasPrivate(context, privateKey);
  74. if (result.IsJust() && result.FromJust() &&
  75. GetHandle()->GetPrivate(context, privateKey).ToLocal(&value))
  76. return gin::ConvertFromV8(isolate(), value, out);
  77. return false;
  78. }
  79. template <typename T>
  80. bool SetHidden(base::StringPiece key, T val) {
  81. v8::Local<v8::Value> v8_value;
  82. if (!gin::TryConvertToV8(isolate(), val, &v8_value))
  83. return false;
  84. v8::Local<v8::Context> context = isolate()->GetCurrentContext();
  85. v8::Local<v8::Private> privateKey =
  86. v8::Private::ForApi(isolate(), gin::StringToV8(isolate(), key));
  87. v8::Maybe<bool> result =
  88. GetHandle()->SetPrivate(context, privateKey, v8_value);
  89. return !result.IsNothing() && result.FromJust();
  90. }
  91. template <typename T>
  92. bool SetMethod(base::StringPiece key, const T& callback) {
  93. auto context = isolate()->GetCurrentContext();
  94. auto templ = CallbackTraits<T>::CreateTemplate(isolate(), callback);
  95. return GetHandle()
  96. ->Set(context, gin::StringToV8(isolate(), key),
  97. templ->GetFunction(context).ToLocalChecked())
  98. .ToChecked();
  99. }
  100. template <typename K, typename V>
  101. bool SetGetter(const K& key,
  102. const V& val,
  103. v8::PropertyAttribute attribute = v8::None) {
  104. AccessorValue<V> acc_value;
  105. acc_value.Value = val;
  106. v8::Local<v8::Value> v8_value_accessor;
  107. if (!gin::TryConvertToV8(isolate(), acc_value, &v8_value_accessor))
  108. return false;
  109. auto context = isolate()->GetCurrentContext();
  110. return GetHandle()
  111. ->SetAccessor(
  112. context, gin::StringToV8(isolate(), key),
  113. [](v8::Local<v8::Name> property_name,
  114. const v8::PropertyCallbackInfo<v8::Value>& info) {
  115. AccessorValue<V> acc_value;
  116. if (!gin::ConvertFromV8(info.GetIsolate(), info.Data(),
  117. &acc_value))
  118. return;
  119. V val = acc_value.Value;
  120. v8::Local<v8::Value> v8_value;
  121. if (gin::TryConvertToV8(info.GetIsolate(), val, &v8_value))
  122. info.GetReturnValue().Set(v8_value);
  123. },
  124. nullptr, v8_value_accessor, v8::DEFAULT, attribute)
  125. .ToChecked();
  126. }
  127. template <typename T>
  128. bool SetReadOnly(base::StringPiece key, const T& val) {
  129. v8::Local<v8::Value> v8_value;
  130. if (!gin::TryConvertToV8(isolate(), val, &v8_value))
  131. return false;
  132. v8::Maybe<bool> result = GetHandle()->DefineOwnProperty(
  133. isolate()->GetCurrentContext(), gin::StringToV8(isolate(), key),
  134. v8_value, v8::ReadOnly);
  135. return !result.IsNothing() && result.FromJust();
  136. }
  137. // Note: If we plan to add more Set methods, consider adding an option instead
  138. // of copying code.
  139. template <typename T>
  140. bool SetReadOnlyNonConfigurable(base::StringPiece key, T val) {
  141. v8::Local<v8::Value> v8_value;
  142. if (!gin::TryConvertToV8(isolate(), val, &v8_value))
  143. return false;
  144. v8::Maybe<bool> result = GetHandle()->DefineOwnProperty(
  145. isolate()->GetCurrentContext(), gin::StringToV8(isolate(), key),
  146. v8_value,
  147. static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
  148. return !result.IsNothing() && result.FromJust();
  149. }
  150. bool Has(base::StringPiece key) const {
  151. v8::Maybe<bool> result = GetHandle()->Has(isolate()->GetCurrentContext(),
  152. gin::StringToV8(isolate(), key));
  153. return !result.IsNothing() && result.FromJust();
  154. }
  155. bool Delete(base::StringPiece key) {
  156. v8::Maybe<bool> result = GetHandle()->Delete(
  157. isolate()->GetCurrentContext(), gin::StringToV8(isolate(), key));
  158. return !result.IsNothing() && result.FromJust();
  159. }
  160. bool IsEmpty() const { return isolate() == nullptr || GetHandle().IsEmpty(); }
  161. v8::Local<v8::Object> GetHandle() const {
  162. return gin::ConvertToV8(isolate(),
  163. *static_cast<const gin::Dictionary*>(this))
  164. .As<v8::Object>();
  165. }
  166. private:
  167. // DO NOT ADD ANY DATA MEMBER.
  168. };
  169. } // namespace gin_helper
  170. namespace gin {
  171. template <>
  172. struct Converter<gin_helper::Dictionary> {
  173. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  174. gin_helper::Dictionary val) {
  175. return val.GetHandle();
  176. }
  177. static bool FromV8(v8::Isolate* isolate,
  178. v8::Local<v8::Value> val,
  179. gin_helper::Dictionary* out) {
  180. gin::Dictionary gdict(isolate);
  181. if (!ConvertFromV8(isolate, val, &gdict))
  182. return false;
  183. *out = gin_helper::Dictionary(gdict);
  184. return true;
  185. }
  186. };
  187. } // namespace gin
  188. #endif // SHELL_COMMON_GIN_HELPER_DICTIONARY_H_