@auto_js/napi 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +4 -0
- package/_module.cc +2 -0
- package/api/api.cc +1 -0
- package/api/callback_info.cc +1 -1
- package/api/napi_scheduler.cc +21 -0
- package/api/napi_scheduler.h.cc +16 -0
- package/api/threadsafe_function.cc +6 -6
- package/api/unmaybe.cc +36 -0
- package/handle/remote.cc +22 -17
- package/handle/value.cc +14 -3
- package/package.json +4 -4
- package/support/callback.cc +52 -48
- package/support/callback_storage.cc +11 -4
- package/support/class_template_storage.cc +6 -5
- package/support/environment.cc +1 -0
- package/support/environment.h.cc +8 -3
- package/support/environment_fwd.cc +4 -2
- package/support/error_scope.cc +11 -5
- package/support/host.cc +43 -5
- package/support/host.h.cc +13 -2
- package/support/initialize.h.cc +3 -1
- package/support/lock.cc +40 -0
- package/support/lock.h.cc +64 -0
- package/support/promise.cc +28 -18
- package/transfer/accept.cc +1 -1
- package/transfer/accept.h.cc +21 -18
- package/transfer/transfer_list.cc +132 -0
- package/transfer/visit.cc +183 -123
- package/value/array.cc +6 -1
- package/value/array.h.cc +8 -3
- package/value/array_buffer.cc +19 -15
- package/value/array_buffer.h.cc +18 -16
- package/value/class.cc +37 -16
- package/value/class.h.cc +5 -4
- package/value/external.cc +7 -7
- package/value/function.cc +15 -15
- package/value/function.h.cc +6 -5
- package/value/object.cc +2 -2
- package/value/object.h.cc +2 -2
- package/value/record.cc +8 -2
- package/value/record.h.cc +8 -2
package/transfer/visit.cc
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export module napi_js:visit;
|
|
2
|
+
import :lock;
|
|
2
3
|
import :utility;
|
|
3
4
|
import :value;
|
|
4
5
|
import std;
|
|
@@ -24,7 +25,7 @@ struct visit_property_name {
|
|
|
24
25
|
auto operator()(napi_value subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
25
26
|
return visit_.get().lookup_or_visit(subject, [ & ] -> accept_target_t<Accept> {
|
|
26
27
|
auto accept_as = [ & ]<class Tag>(Tag tag) -> auto {
|
|
27
|
-
auto value = value_of{
|
|
28
|
+
auto value = value_of{visit_.get().lock(), local_of<Tag>::from(subject)};
|
|
28
29
|
return accept(tag, *this, value);
|
|
29
30
|
};
|
|
30
31
|
switch (napi::invoke(napi_typeof, napi_env{visit_.get()}, subject)) {
|
|
@@ -36,7 +37,7 @@ struct visit_property_name {
|
|
|
36
37
|
});
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
[[nodiscard]] auto
|
|
40
|
+
[[nodiscard]] auto lock() const -> const auto& { return visit_.get().lock(); }
|
|
40
41
|
|
|
41
42
|
private:
|
|
42
43
|
std::reference_wrapper<Visit> visit_;
|
|
@@ -50,34 +51,34 @@ struct visit_napi_key_literal {
|
|
|
50
51
|
|
|
51
52
|
auto operator()(const auto& /*could_be_literally_anything*/, const auto& accept_or_visit) -> napi_value {
|
|
52
53
|
const auto make = util::overloaded{
|
|
53
|
-
[](
|
|
54
|
-
auto* value = napi::invoke(node_api_create_property_key_latin1, napi_env{
|
|
54
|
+
[](environment_lock_witness lock, std::string_view subject) -> napi::local_of<string_tag_of<char>> {
|
|
55
|
+
auto* value = napi::invoke(node_api_create_property_key_latin1, napi_env{lock}, subject.data(), subject.length());
|
|
55
56
|
return napi::local_of<string_tag_of<char>>::from(value);
|
|
56
57
|
},
|
|
57
|
-
[](
|
|
58
|
-
auto* value = napi::invoke(node_api_create_property_key_utf16, napi_env{
|
|
58
|
+
[](environment_lock_witness lock, std::u16string_view subject) -> napi::local_of<string_tag_of<char16_t>> {
|
|
59
|
+
auto* value = napi::invoke(node_api_create_property_key_utf16, napi_env{lock}, subject.data(), subject.length());
|
|
59
60
|
return napi::local_of<string_tag_of<char16_t>>::from(value);
|
|
60
61
|
},
|
|
61
|
-
[](
|
|
62
|
-
auto* value = napi::invoke(node_api_create_property_key_utf8, napi_env{
|
|
62
|
+
[](environment_lock_witness lock, std::u8string_view subject) -> napi::local_of<string_tag_of<char8_t>> {
|
|
63
|
+
auto* value = napi::invoke(node_api_create_property_key_utf8, napi_env{lock}, reinterpret_cast<const char*>(subject.data()), subject.length());
|
|
63
64
|
return napi::local_of<string_tag_of<char8_t>>::from(value);
|
|
64
65
|
},
|
|
65
66
|
};
|
|
66
67
|
if (local_key_ == napi_value{}) {
|
|
67
68
|
constexpr auto key = util::make_consteval_string_view(Key);
|
|
68
|
-
auto&
|
|
69
|
-
auto storage =
|
|
69
|
+
const auto& lock = accept_or_visit.lock();
|
|
70
|
+
auto storage = lock->string_table_storage(Key);
|
|
70
71
|
if (storage) {
|
|
71
72
|
auto& reference = *storage;
|
|
72
73
|
if (reference) {
|
|
73
|
-
local_key_ = reference.get(
|
|
74
|
+
local_key_ = reference.get(lock);
|
|
74
75
|
} else {
|
|
75
|
-
auto value = make(
|
|
76
|
-
reference.reset(
|
|
76
|
+
auto value = make(lock, key);
|
|
77
|
+
reference.reset(lock, value);
|
|
77
78
|
local_key_ = napi_value{value};
|
|
78
79
|
}
|
|
79
80
|
} else {
|
|
80
|
-
return make(
|
|
81
|
+
return make(lock, key);
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
return local_key_;
|
|
@@ -90,7 +91,7 @@ struct visit_napi_key_literal {
|
|
|
90
91
|
// Base napi visitor implementing all functionality. Napi doesn't give us granular information like
|
|
91
92
|
// "is this a latin1 string" and all checks must be made at once. So it's structured it great deal
|
|
92
93
|
// differently than the v8 visitor.
|
|
93
|
-
template <
|
|
94
|
+
template <class Lock, class Ref>
|
|
94
95
|
struct visit_value;
|
|
95
96
|
|
|
96
97
|
template <class Meta>
|
|
@@ -98,85 +99,85 @@ using visit_value_with = visit_value<
|
|
|
98
99
|
typename Meta::visit_context_type,
|
|
99
100
|
typename Meta::accept_reference_type>;
|
|
100
101
|
|
|
101
|
-
template <
|
|
102
|
+
template <class Lock, class Reference>
|
|
102
103
|
struct visit_value : reference_map_t<Reference, reference_map_type> {
|
|
103
104
|
public:
|
|
104
105
|
using reference_map_t<Reference, reference_map_type>::lookup_or_visit;
|
|
105
106
|
|
|
106
|
-
visit_value(auto* /*transfer*/,
|
|
107
|
-
|
|
107
|
+
visit_value(auto* /*transfer*/, const Lock& lock) :
|
|
108
|
+
lock_{lock} {}
|
|
108
109
|
|
|
109
|
-
// If the
|
|
110
|
-
//
|
|
110
|
+
// If the `immediate` operation is defined: this operation will first perform a
|
|
111
|
+
// reference map lookup, then delegate to the `immediate` operation if not found.
|
|
111
112
|
template <class Tag, class Accept>
|
|
112
|
-
auto operator()(local_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept>
|
|
113
|
-
requires requires { immediate(subject, accept); } {
|
|
114
|
-
return lookup_or_visit(subject, [ & ] -> accept_target_t<Accept> {
|
|
115
|
-
return immediate(subject, accept);
|
|
113
|
+
auto operator()(this auto& self, local_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept>
|
|
114
|
+
requires requires { self.immediate(subject, accept); } {
|
|
115
|
+
return self.lookup_or_visit(subject, [ & ] -> accept_target_t<Accept> {
|
|
116
|
+
return self.immediate(subject, accept);
|
|
116
117
|
});
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
// Visit operations for non-refable types.
|
|
120
121
|
template <class Accept>
|
|
121
|
-
auto operator()(local_of<null_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
122
|
-
return immediate(subject, accept);
|
|
122
|
+
auto operator()(this auto& self, local_of<null_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
123
|
+
return self.immediate(subject, accept);
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
template <class Accept>
|
|
126
|
-
auto operator()(local_of<undefined_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
127
|
-
return immediate(subject, accept);
|
|
127
|
+
auto operator()(this auto& self, local_of<undefined_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
128
|
+
return self.immediate(subject, accept);
|
|
128
129
|
}
|
|
129
130
|
|
|
130
131
|
template <class Accept>
|
|
131
|
-
auto operator()(local_of<boolean_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
132
|
-
return immediate(subject, accept);
|
|
132
|
+
auto operator()(this auto& self, local_of<boolean_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
133
|
+
return self.immediate(subject, accept);
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
template <class Accept>
|
|
136
|
-
auto operator()(local_of<number_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
137
|
+
auto operator()(this auto& self, local_of<number_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
137
138
|
if (maybe_is_number_int32(subject).value_or(false)) {
|
|
138
|
-
return immediate(local_of<number_tag_of<std::int32_t>>::from(subject), accept);
|
|
139
|
+
return self.immediate(local_of<number_tag_of<std::int32_t>>::from(subject), accept);
|
|
139
140
|
} else {
|
|
140
|
-
return immediate(local_of<number_tag_of<double>>::from(subject), accept);
|
|
141
|
+
return self.immediate(local_of<number_tag_of<double>>::from(subject), accept);
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
144
|
|
|
144
145
|
template <class Accept, class Type>
|
|
145
|
-
auto operator()(local_of<number_tag_of<Type>> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
146
|
-
return immediate(subject, accept);
|
|
146
|
+
auto operator()(this auto& self, local_of<number_tag_of<Type>> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
147
|
+
return self.immediate(subject, accept);
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
// General purpose visit operation which actually performs the type check
|
|
150
151
|
template <class Accept>
|
|
151
|
-
auto operator()(napi_value subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
152
|
+
auto operator()(this auto& self, napi_value subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
152
153
|
|
|
153
154
|
// Check the reference map, and lookup type via napi
|
|
154
|
-
return lookup_or_visit(subject, [ & ] -> accept_target_t<Accept> {
|
|
155
|
+
return self.lookup_or_visit(subject, [ & ] -> accept_target_t<Accept> {
|
|
155
156
|
// This is the pure-napi implementation
|
|
156
157
|
auto slow_path = util::overloaded{
|
|
157
158
|
[ & ] -> accept_target_t<Accept> {
|
|
158
|
-
auto type_of = napi::invoke(napi_typeof, napi_env{
|
|
159
|
+
auto type_of = napi::invoke(napi_typeof, napi_env{self}, subject);
|
|
159
160
|
switch (type_of) {
|
|
160
161
|
case napi_undefined:
|
|
161
|
-
return (
|
|
162
|
+
return self(local_of<undefined_tag>::from(subject), accept);
|
|
162
163
|
case napi_null:
|
|
163
|
-
return (
|
|
164
|
+
return self(local_of<null_tag>::from(subject), accept);
|
|
164
165
|
case napi_boolean:
|
|
165
|
-
return (
|
|
166
|
+
return self(local_of<boolean_tag>::from(subject), accept);
|
|
166
167
|
case napi_number:
|
|
167
|
-
return (
|
|
168
|
+
return self(local_of<number_tag>::from(subject), accept);
|
|
168
169
|
case napi_string:
|
|
169
|
-
return immediate(local_of<string_tag>::from(subject), accept);
|
|
170
|
+
return self.immediate(local_of<string_tag>::from(subject), accept);
|
|
170
171
|
case napi_symbol:
|
|
171
|
-
return immediate(local_of<symbol_tag>::from(subject), accept);
|
|
172
|
+
return self.immediate(local_of<symbol_tag>::from(subject), accept);
|
|
172
173
|
case napi_object:
|
|
173
|
-
return immediate(local_of<object_tag>::from(subject), accept);
|
|
174
|
+
return self.immediate(local_of<object_tag>::from(subject), accept);
|
|
174
175
|
case napi_function:
|
|
175
|
-
return immediate(local_of<function_tag>::from(subject), accept);
|
|
176
|
+
return self.immediate(local_of<function_tag>::from(subject), accept);
|
|
176
177
|
case napi_external:
|
|
177
|
-
return immediate(local_of<external_tag>::from(subject), accept);
|
|
178
|
+
return self.immediate(local_of<external_tag>::from(subject), accept);
|
|
178
179
|
case napi_bigint:
|
|
179
|
-
return immediate(local_of<bigint_tag>::from(subject), accept);
|
|
180
|
+
return self.immediate(local_of<bigint_tag>::from(subject), accept);
|
|
180
181
|
}
|
|
181
182
|
std::unreachable();
|
|
182
183
|
},
|
|
@@ -187,16 +188,16 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
|
|
|
187
188
|
// Universal fast checks
|
|
188
189
|
auto fast_path = util::overloaded{
|
|
189
190
|
[ & ](undefined_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
190
|
-
return fast_is_undefined(napi_env{
|
|
191
|
+
return fast_is_undefined(napi_env{self}, subject) ? self(local_of<undefined_tag>::from(subject), accept) : next();
|
|
191
192
|
},
|
|
192
193
|
[ & ](null_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
193
|
-
return fast_is_null(napi_env{
|
|
194
|
+
return fast_is_null(napi_env{self}, subject) ? self(local_of<null_tag>::from(subject), accept) : next();
|
|
194
195
|
},
|
|
195
196
|
[ & ](boolean_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
196
|
-
if (fast_is_false(napi_env{
|
|
197
|
-
return (
|
|
198
|
-
} else if (fast_is_true(napi_env{
|
|
199
|
-
return (
|
|
197
|
+
if (fast_is_false(napi_env{self}, subject)) {
|
|
198
|
+
return self(local_of<false_tag>::from(subject), accept);
|
|
199
|
+
} else if (fast_is_true(napi_env{self}, subject)) {
|
|
200
|
+
return self(local_of<true_tag>::from(subject), accept);
|
|
200
201
|
} else {
|
|
201
202
|
return next();
|
|
202
203
|
}
|
|
@@ -206,27 +207,27 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
|
|
|
206
207
|
// Extended fast checks
|
|
207
208
|
auto extended_fast_path = util::overloaded{
|
|
208
209
|
[ & ](number_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
209
|
-
return fast_is_number(subject) ? (
|
|
210
|
+
return fast_is_number(subject) ? self(local_of<number_tag>::from(subject), accept) : next();
|
|
210
211
|
},
|
|
211
212
|
[ & ](string_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
212
|
-
return fast_is_string(subject) ? immediate(local_of<string_tag>::from(subject), accept) : next();
|
|
213
|
+
return fast_is_string(subject) ? self.immediate(local_of<string_tag>::from(subject), accept) : next();
|
|
213
214
|
},
|
|
214
215
|
[ & ](bigint_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
215
|
-
return fast_is_bigint(subject) ? immediate(local_of<bigint_tag>::from(subject), accept) : next();
|
|
216
|
+
return fast_is_bigint(subject) ? self.immediate(local_of<bigint_tag>::from(subject), accept) : next();
|
|
216
217
|
},
|
|
217
218
|
[ & ](date_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
218
|
-
return napi::invoke(napi_is_date, napi_env{
|
|
219
|
+
return napi::invoke(napi_is_date, napi_env{self}, subject) ? self.immediate(local_of<date_tag>::from(subject), accept) : next();
|
|
219
220
|
},
|
|
220
221
|
[ & ](list_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
221
|
-
return fast_is_array(subject) ? immediate(local_of<list_tag>::from(subject), accept) : next();
|
|
222
|
+
return fast_is_array(subject) ? self.immediate(local_of<list_tag>::from(subject), accept) : next();
|
|
222
223
|
},
|
|
223
224
|
[ & ](object_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
224
225
|
// nb: You can't really skip the subsequent is promise, is date, is arraybuffer, etc
|
|
225
226
|
// checks. We don't really want to accept those types here, I don't think..
|
|
226
|
-
return fast_is_object(subject) ? immediate(local_of<object_tag>::from(subject), accept) : next();
|
|
227
|
+
return fast_is_object(subject) ? self.immediate(local_of<object_tag>::from(subject), accept) : next();
|
|
227
228
|
},
|
|
228
229
|
[ & ](function_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
229
|
-
return fast_is_function(subject) ? immediate(local_of<function_tag>::from(subject), accept) : next();
|
|
230
|
+
return fast_is_function(subject) ? self.immediate(local_of<function_tag>::from(subject), accept) : next();
|
|
230
231
|
},
|
|
231
232
|
|
|
232
233
|
// Skip these, otherwise `number_tag` and `string_tag` are invoked twice, which we don't
|
|
@@ -246,19 +247,19 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
|
|
|
246
247
|
}
|
|
247
248
|
|
|
248
249
|
template <class Accept>
|
|
249
|
-
auto operator()(local_of<data_block_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
250
|
-
return lookup_or_visit(subject, [ & ] -> accept_target_t<Accept> {
|
|
250
|
+
auto operator()(this auto& self, local_of<data_block_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
251
|
+
return self.lookup_or_visit(subject, [ & ] -> accept_target_t<Accept> {
|
|
251
252
|
return util::template_traverse(
|
|
252
253
|
accept_tags_of_v<Accept>,
|
|
253
254
|
util::overloaded{
|
|
254
255
|
// Fast paths
|
|
255
|
-
[ & ](data_block_tag /*tag*/, auto /*next*/) -> accept_target_t<Accept> { return accept_tagged(subject, accept); },
|
|
256
|
+
[ & ](data_block_tag /*tag*/, auto /*next*/) -> accept_target_t<Accept> { return self.accept_tagged(subject, accept); },
|
|
256
257
|
[ & ](array_buffer_tag /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
|
|
257
258
|
[ & ](shared_array_buffer_tag /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
|
|
258
259
|
|
|
259
260
|
// Slow path
|
|
260
261
|
[ & ] -> accept_target_t<Accept> {
|
|
261
|
-
return immediate(subject, accept);
|
|
262
|
+
return self.immediate(subject, accept);
|
|
262
263
|
}
|
|
263
264
|
}
|
|
264
265
|
);
|
|
@@ -266,88 +267,88 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
|
|
|
266
267
|
}
|
|
267
268
|
|
|
268
269
|
// extras
|
|
269
|
-
[[nodiscard]] auto
|
|
270
|
-
explicit operator napi_env() const { return napi_env{
|
|
270
|
+
[[nodiscard]] auto lock() const -> const Lock& { return lock_; }
|
|
271
|
+
explicit operator napi_env() const { return napi_env{lock_.get()}; }
|
|
271
272
|
consteval static auto types(auto /*recursive*/) { return util::type_pack{}; }
|
|
272
273
|
|
|
273
|
-
|
|
274
|
+
protected:
|
|
274
275
|
// I think this only applies to `symbol_tag`
|
|
275
276
|
template <class Accept, class Tag>
|
|
276
277
|
requires std::is_convertible_v<Tag, primitive_tag>
|
|
277
|
-
auto immediate(local_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
278
|
-
return accept_tagged(subject, accept);
|
|
278
|
+
auto immediate(this auto& self, local_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
279
|
+
return self.accept_tagged(subject, accept);
|
|
279
280
|
}
|
|
280
281
|
|
|
281
282
|
// strings
|
|
282
283
|
template <class Accept>
|
|
283
|
-
auto immediate(local_of<string_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
284
|
+
auto immediate(this auto& self, local_of<string_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
284
285
|
if (maybe_is_string_latin1(subject).value_or(false)) {
|
|
285
|
-
return accept_tagged(local_of<string_tag_of<char>>::from(subject), accept);
|
|
286
|
+
return self.accept_tagged(local_of<string_tag_of<char>>::from(subject), accept);
|
|
286
287
|
} else {
|
|
287
|
-
return accept_tagged(local_of<string_tag_of<char16_t>>::from(subject), accept);
|
|
288
|
+
return self.accept_tagged(local_of<string_tag_of<char16_t>>::from(subject), accept);
|
|
288
289
|
}
|
|
289
290
|
}
|
|
290
291
|
|
|
291
292
|
// bigint
|
|
292
293
|
template <class Accept>
|
|
293
|
-
auto immediate(local_of<bigint_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
294
|
-
return accept_tagged(local_of<bigint_tag_of<bigint>>::from(subject), accept);
|
|
294
|
+
auto immediate(this auto& self, local_of<bigint_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
295
|
+
return self.accept_tagged(local_of<bigint_tag_of<bigint>>::from(subject), accept);
|
|
295
296
|
}
|
|
296
297
|
|
|
297
|
-
//
|
|
298
|
+
// objects
|
|
298
299
|
template <class Accept>
|
|
299
|
-
auto immediate(local_of<object_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
300
|
-
if (napi::invoke(napi_is_array, napi_env{
|
|
301
|
-
return immediate(local_of<list_tag>::from(subject), accept);
|
|
302
|
-
} else if (napi::invoke(napi_is_date, napi_env{
|
|
303
|
-
return immediate(local_of<date_tag>::from(subject), accept);
|
|
304
|
-
} else if (napi::invoke(napi_is_typedarray, napi_env{
|
|
305
|
-
return immediate(local_of<typed_array_tag>::from(subject), accept);
|
|
306
|
-
} else if (napi::invoke(napi_is_dataview, napi_env{
|
|
307
|
-
return immediate(local_of<data_view_tag>::from(subject), accept);
|
|
308
|
-
} else if (maybe_is_shared_array_buffer(
|
|
309
|
-
return immediate(local_of<shared_array_buffer_tag>::from(subject), accept);
|
|
310
|
-
} else if (is_object_array_buffer(
|
|
311
|
-
return immediate(local_of<array_buffer_tag>::from(subject), accept);
|
|
312
|
-
} else if (napi::invoke(napi_is_promise, napi_env{
|
|
313
|
-
return immediate(local_of<promise_tag>::from(subject), accept);
|
|
300
|
+
auto immediate(this auto& self, local_of<object_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
301
|
+
if (napi::invoke(napi_is_array, napi_env{self}, subject)) {
|
|
302
|
+
return self.immediate(local_of<list_tag>::from(subject), accept);
|
|
303
|
+
} else if (napi::invoke(napi_is_date, napi_env{self}, subject)) {
|
|
304
|
+
return self.immediate(local_of<date_tag>::from(subject), accept);
|
|
305
|
+
} else if (napi::invoke(napi_is_typedarray, napi_env{self}, subject)) {
|
|
306
|
+
return self.immediate(local_of<typed_array_tag>::from(subject), accept);
|
|
307
|
+
} else if (napi::invoke(napi_is_dataview, napi_env{self}, subject)) {
|
|
308
|
+
return self.immediate(local_of<data_view_tag>::from(subject), accept);
|
|
309
|
+
} else if (maybe_is_shared_array_buffer(napi_env{self}, subject).value_or(false)) {
|
|
310
|
+
return self.immediate(local_of<shared_array_buffer_tag>::from(subject), accept);
|
|
311
|
+
} else if (is_object_array_buffer(napi_env{self}, subject)) {
|
|
312
|
+
return self.immediate(local_of<array_buffer_tag>::from(subject), accept);
|
|
313
|
+
} else if (napi::invoke(napi_is_promise, napi_env{self}, subject)) {
|
|
314
|
+
return self.immediate(local_of<promise_tag>::from(subject), accept);
|
|
314
315
|
} else {
|
|
315
|
-
return immediate(local_of<dictionary_tag>::from(subject), accept);
|
|
316
|
+
return self.immediate(local_of<dictionary_tag>::from(subject), accept);
|
|
316
317
|
}
|
|
317
318
|
}
|
|
318
319
|
|
|
319
320
|
// date
|
|
320
321
|
template <class Accept>
|
|
321
|
-
auto immediate(local_of<date_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
322
|
-
return accept_tagged(subject, accept);
|
|
322
|
+
auto immediate(this auto& self, local_of<date_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
323
|
+
return self.accept_tagged(subject, accept);
|
|
323
324
|
}
|
|
324
325
|
|
|
325
326
|
// data blocks
|
|
326
327
|
template <class Accept>
|
|
327
|
-
auto immediate(local_of<data_block_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
328
|
-
if (is_data_block_array_buffer(
|
|
329
|
-
return immediate(local_of<array_buffer_tag>::from(subject), accept);
|
|
328
|
+
auto immediate(this auto& self, local_of<data_block_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
329
|
+
if (is_data_block_array_buffer(napi_env{self}, subject)) {
|
|
330
|
+
return self.immediate(local_of<array_buffer_tag>::from(subject), accept);
|
|
330
331
|
} else {
|
|
331
|
-
return immediate(local_of<shared_array_buffer_tag>::from(subject), accept);
|
|
332
|
+
return self.immediate(local_of<shared_array_buffer_tag>::from(subject), accept);
|
|
332
333
|
}
|
|
333
334
|
}
|
|
334
335
|
|
|
335
336
|
template <class Accept, class Tag>
|
|
336
337
|
requires std::is_convertible_v<Tag, data_block_tag>
|
|
337
|
-
auto immediate(local_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
338
|
-
return accept_tagged(subject, accept);
|
|
338
|
+
auto immediate(this auto& self, local_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
339
|
+
return self.accept_tagged(subject, accept);
|
|
339
340
|
}
|
|
340
341
|
|
|
341
342
|
// array buffer views
|
|
342
343
|
template <class Accept>
|
|
343
|
-
auto immediate(local_of<typed_array_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
344
|
-
auto bound_subject_variant = value_for_typed_array::make_bound(
|
|
344
|
+
auto immediate(this auto& self, local_of<typed_array_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
345
|
+
auto bound_subject_variant = value_for_typed_array::make_bound(self.lock(), subject);
|
|
345
346
|
if (bound_subject_variant.index() == std::variant_npos) {
|
|
346
347
|
std::unreachable();
|
|
347
348
|
} else {
|
|
348
349
|
return std::visit(
|
|
349
350
|
[ & ]<class Tag>(value_of<Tag> value) -> accept_target_t<Accept> {
|
|
350
|
-
return accept(Tag{},
|
|
351
|
+
return accept(Tag{}, self, value);
|
|
351
352
|
},
|
|
352
353
|
bound_subject_variant
|
|
353
354
|
);
|
|
@@ -355,51 +356,95 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
|
|
|
355
356
|
}
|
|
356
357
|
|
|
357
358
|
template <class Accept>
|
|
358
|
-
auto immediate(local_of<data_view_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
359
|
-
return accept_tagged(subject, accept);
|
|
359
|
+
auto immediate(this auto& self, local_of<data_view_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
360
|
+
return self.accept_tagged(subject, accept);
|
|
360
361
|
}
|
|
361
362
|
|
|
362
363
|
// externals
|
|
363
364
|
template <class Accept>
|
|
364
|
-
auto immediate(local_of<external_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
365
|
-
return accept_tagged(subject, accept);
|
|
365
|
+
auto immediate(this auto& self, local_of<external_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
366
|
+
return self.accept_tagged(subject, accept);
|
|
366
367
|
}
|
|
367
368
|
|
|
368
369
|
// promise
|
|
369
370
|
template <class Accept>
|
|
370
|
-
auto immediate(local_of<promise_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
371
|
-
return accept_tagged(subject, accept);
|
|
371
|
+
auto immediate(this auto& self, local_of<promise_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
372
|
+
return self.accept_tagged(subject, accept);
|
|
372
373
|
}
|
|
373
374
|
|
|
374
375
|
// function
|
|
375
376
|
template <class Accept>
|
|
376
|
-
auto immediate(local_of<function_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
377
|
-
return accept_tagged(subject, accept);
|
|
377
|
+
auto immediate(this auto& self, local_of<function_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
378
|
+
return self.accept_tagged(subject, accept);
|
|
378
379
|
}
|
|
379
380
|
|
|
380
381
|
// array
|
|
381
|
-
template <class Accept>
|
|
382
|
-
auto immediate(local_of<list_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
383
|
-
auto target = napi::value_of{
|
|
384
|
-
auto visit_entry = visit_entry_pair<visit_property_name<
|
|
382
|
+
template <class Visit, class Accept>
|
|
383
|
+
auto immediate(this Visit& self, local_of<list_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
384
|
+
auto target = napi::value_of{self.lock(), local_of<list_tag>::from(subject)};
|
|
385
|
+
auto visit_entry = visit_entry_pair<visit_property_name<Visit>, Visit&>{self};
|
|
385
386
|
return accept(list_tag{}, visit_entry, target);
|
|
386
387
|
}
|
|
387
388
|
|
|
388
389
|
// object / record
|
|
389
|
-
template <class Accept>
|
|
390
|
-
auto immediate(local_of<dictionary_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
391
|
-
auto target = napi::value_of{
|
|
392
|
-
auto visit_entry = visit_entry_pair<visit_property_name<
|
|
390
|
+
template <class Visit, class Accept>
|
|
391
|
+
auto immediate(this Visit& self, local_of<dictionary_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
392
|
+
auto target = napi::value_of{self.lock(), local_of<dictionary_tag>::from(subject)};
|
|
393
|
+
auto visit_entry = visit_entry_pair<visit_property_name<Visit>, Visit&>{self};
|
|
393
394
|
return accept(dictionary_tag{}, visit_entry, target);
|
|
394
395
|
}
|
|
395
396
|
|
|
396
397
|
// Convenience function which wraps in `napi::value_of` and invokes `accept`.
|
|
397
398
|
template <class Tag, class Accept>
|
|
398
|
-
[[nodiscard]] auto accept_tagged(local_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
399
|
-
return accept(Tag{},
|
|
399
|
+
[[nodiscard]] auto accept_tagged(this auto& self, local_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
400
|
+
return accept(Tag{}, self, napi::value_of{self.lock(), subject});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
private:
|
|
404
|
+
std::reference_wrapper<const Lock> lock_;
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
// Visitor with transfer delegate
|
|
408
|
+
template <class Lock, class Reference, class Delegate>
|
|
409
|
+
struct visit_value_delegate;
|
|
410
|
+
|
|
411
|
+
template <class Meta, class Delegate>
|
|
412
|
+
using visit_value_delegate_with =
|
|
413
|
+
visit_value_delegate<typename Meta::visit_context_type, typename Meta::accept_reference_type, Delegate>;
|
|
414
|
+
|
|
415
|
+
template <class Lock, class Reference, class Delegate>
|
|
416
|
+
struct visit_value_delegate : visit_value<Lock, Reference> {
|
|
417
|
+
private:
|
|
418
|
+
using visit_type = visit_value<Lock, Reference>;
|
|
419
|
+
|
|
420
|
+
public:
|
|
421
|
+
visit_value_delegate(auto* transfer, const Lock& lock, Delegate& delegate) :
|
|
422
|
+
visit_type{transfer, lock},
|
|
423
|
+
delegate_{delegate} {}
|
|
424
|
+
|
|
425
|
+
using visit_type::operator();
|
|
426
|
+
using visit_type::immediate;
|
|
427
|
+
|
|
428
|
+
template <class Accept>
|
|
429
|
+
auto immediate(this auto& self, local_of<object_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
430
|
+
return self.claim_or_immediate(subject, accept);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
template <class Accept>
|
|
434
|
+
auto immediate(this auto& self, local_of<data_block_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
435
|
+
return self.claim_or_immediate(subject, accept);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
private:
|
|
439
|
+
template <class Accept>
|
|
440
|
+
auto claim_or_immediate(this auto& self, auto subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
441
|
+
if (auto claimed = self.delegate_.get()(subject, self, accept)) {
|
|
442
|
+
return *std::move(claimed);
|
|
443
|
+
}
|
|
444
|
+
return self.visit_value<Lock, Reference>::immediate(subject, accept);
|
|
400
445
|
}
|
|
401
446
|
|
|
402
|
-
std::reference_wrapper<
|
|
447
|
+
std::reference_wrapper<Delegate> delegate_;
|
|
403
448
|
};
|
|
404
449
|
|
|
405
450
|
// Forward `value_of<T>` back to acceptor
|
|
@@ -409,7 +454,7 @@ struct visit_napi_value_of {
|
|
|
409
454
|
using visit_type = visit_value_with<Meta>;
|
|
410
455
|
|
|
411
456
|
public:
|
|
412
|
-
constexpr explicit visit_napi_value_of(auto* transfer, auto&
|
|
457
|
+
constexpr explicit visit_napi_value_of(auto* transfer, const auto& lock) : visit_{transfer, lock} {}
|
|
413
458
|
|
|
414
459
|
template <class Accept>
|
|
415
460
|
constexpr auto operator()(value_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
@@ -451,6 +496,21 @@ struct visit<Meta, napi::local_of<Tag>> : napi::visit_value_with<Meta> {
|
|
|
451
496
|
using napi::visit_value_with<Meta>::visit_value_with;
|
|
452
497
|
};
|
|
453
498
|
|
|
499
|
+
// `transferee_visit_subject` subject visitor
|
|
500
|
+
template <class Meta, class Tag, class Delegate>
|
|
501
|
+
struct visit<Meta, transferee_visit_subject<napi::local_of<Tag>, Delegate>> : napi::visit_value_delegate_with<Meta, Delegate> {
|
|
502
|
+
private:
|
|
503
|
+
using visit_type = napi::visit_value_delegate_with<Meta, Delegate>;
|
|
504
|
+
|
|
505
|
+
public:
|
|
506
|
+
using visit_type::visit_type;
|
|
507
|
+
|
|
508
|
+
template <class Accept>
|
|
509
|
+
auto operator()(const transferee_visit_subject<napi::local_of<Tag>, Delegate>& subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
510
|
+
return util::invoke_as<visit_type>(*this, *subject, accept);
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
|
|
454
514
|
// Pass through `value_of<Tag>`
|
|
455
515
|
template <class Meta, class Tag>
|
|
456
516
|
struct visit<Meta, napi::value_of<Tag>> : napi::visit_napi_value_of<Meta, Tag> {
|
package/value/array.cc
CHANGED
|
@@ -22,7 +22,12 @@ value_for_vector::iterator::iterator(value_for_vector subject, size_type index)
|
|
|
22
22
|
index_{index} {}
|
|
23
23
|
|
|
24
24
|
auto value_for_vector::iterator::operator*() const -> value_type {
|
|
25
|
-
|
|
25
|
+
auto lock = subject_.lock();
|
|
26
|
+
auto* subject = napi_value{subject_};
|
|
27
|
+
if (subject_.maybe_sparse_ && !fast_has_element(lock, subject, index_)) {
|
|
28
|
+
throw js::type_error{u"Sparse arrays are not supported"};
|
|
29
|
+
}
|
|
30
|
+
return value_type::from(fast_get_element(lock, subject, index_));
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
} // namespace js::napi
|
package/value/array.h.cc
CHANGED
|
@@ -8,15 +8,20 @@ namespace js::napi {
|
|
|
8
8
|
class value_for_vector : public value_next<vector_tag> {
|
|
9
9
|
public:
|
|
10
10
|
class iterator;
|
|
11
|
-
using
|
|
12
|
-
|
|
11
|
+
using value_type = local_of<>;
|
|
12
|
+
|
|
13
|
+
value_for_vector() = default;
|
|
14
|
+
value_for_vector(environment_lock_witness lock, local_of<vector_tag> value, bool maybe_sparse = true) :
|
|
15
|
+
value_next{lock, value},
|
|
16
|
+
maybe_sparse_{maybe_sparse} {}
|
|
13
17
|
|
|
14
18
|
[[nodiscard]] auto begin() const -> iterator;
|
|
15
19
|
[[nodiscard]] auto end() const -> iterator;
|
|
16
20
|
[[nodiscard]] auto size() const -> std::uint32_t;
|
|
17
21
|
|
|
18
22
|
private:
|
|
19
|
-
|
|
23
|
+
bool maybe_sparse_ : 1 = true;
|
|
24
|
+
mutable std::uint32_t size_ : 31 {};
|
|
20
25
|
};
|
|
21
26
|
|
|
22
27
|
class value_for_vector::iterator : public util::random_access_iterator_facade<std::int32_t, std::int64_t> {
|