dictionary.h 7.8 KB

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