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