@auto_js/napi 0.0.1 → 0.0.2
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 +10 -4
- package/README.md +30 -3
- package/_module.cc +12 -10
- package/api/api.cc +8 -7
- package/api/callback_info.cc +1 -7
- package/api/finalizer.cc +1 -4
- package/api/invoke.cc +4 -9
- package/api/uv_dlib.cc +27 -0
- package/api/uv_dlib.h.cc +21 -0
- package/api/uv_handle.cc +9 -9
- package/api/uv_scheduler.cc +11 -17
- package/api/uv_scheduler.h.cc +3 -6
- package/handle/bound_value.cc +4 -7
- package/handle/reference.cc +9 -5
- package/handle/remote.cc +11 -17
- package/handle/types.cc +61 -46
- package/handle/value.cc +12 -14
- package/package.json +7 -6
- package/support/callback.cc +7 -19
- package/support/callback_storage.cc +4 -9
- package/support/class_template_storage.cc +4 -6
- package/support/container.cc +9 -10
- package/support/environment.cc +32 -20
- package/support/environment.h.cc +8 -18
- package/support/environment_fwd.cc +1 -2
- package/support/error_scope.cc +0 -2
- package/support/initialize.h.cc +2 -5
- package/support/promise.cc +3 -10
- package/support/string_table.cc +3 -5
- package/support/utility.cc +54 -28
- package/transfer/accept.cc +131 -327
- package/transfer/accept.h.cc +390 -0
- package/transfer/visit.cc +201 -132
- package/value/array.cc +1 -3
- package/value/array.h.cc +5 -11
- package/value/array_buffer.cc +109 -0
- package/value/array_buffer.h.cc +150 -0
- package/value/class.cc +12 -21
- package/value/class.h.cc +5 -10
- package/value/external.cc +6 -10
- package/value/function.cc +5 -12
- package/value/function.h.cc +2 -9
- package/value/object.cc +2 -6
- package/value/object.h.cc +7 -15
- package/value/primitive.cc +12 -81
- package/value/primitive.h.cc +6 -64
- package/value/record.cc +38 -0
- package/value/record.h.cc +39 -0
- package/value/value.cc +8 -8
- package/value/dictionary.cc +0 -33
- package/value/dictionary.h.cc +0 -56
package/transfer/visit.cc
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
|
-
module;
|
|
2
|
-
#include <functional>
|
|
3
|
-
#include <utility>
|
|
4
1
|
export module napi_js:visit;
|
|
5
|
-
import :api;
|
|
6
2
|
import :container;
|
|
7
|
-
import :environment_fwd;
|
|
8
|
-
import :utility;
|
|
9
3
|
import :value;
|
|
4
|
+
import std;
|
|
10
5
|
import util;
|
|
6
|
+
import v8;
|
|
11
7
|
|
|
12
|
-
namespace js {
|
|
13
|
-
using namespace napi;
|
|
8
|
+
namespace js::napi {
|
|
14
9
|
|
|
15
10
|
// Instantiated in the acceptor that corresponds to a napi visitor
|
|
16
|
-
struct
|
|
11
|
+
struct reference_map_type {
|
|
17
12
|
template <class Type>
|
|
18
13
|
using type = napi::value_map<Type>;
|
|
19
14
|
};
|
|
@@ -21,24 +16,22 @@ struct napi_reference_map_type {
|
|
|
21
16
|
// Visitor which may visit only property names. `symbol` should probably be rethought since they are
|
|
22
17
|
// not cloneable.
|
|
23
18
|
template <class Visit>
|
|
24
|
-
struct
|
|
19
|
+
struct visit_property_name {
|
|
25
20
|
public:
|
|
26
|
-
explicit
|
|
21
|
+
explicit visit_property_name(Visit& visit) : visit_{visit} {}
|
|
27
22
|
|
|
28
23
|
template <class Accept>
|
|
29
24
|
auto operator()(napi_value subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
30
|
-
return visit_.get().lookup_or_visit(
|
|
25
|
+
return visit_.get().lookup_or_visit(subject, [ & ]() -> accept_target_t<Accept> {
|
|
26
|
+
auto accept_as = [ & ]<class Tag>(Tag tag) -> auto {
|
|
27
|
+
auto value = bound_value{napi_env{visit_.get()}, value_of<Tag>::from(subject)};
|
|
28
|
+
return accept(tag, *this, value);
|
|
29
|
+
};
|
|
31
30
|
switch (napi::invoke(napi_typeof, napi_env{visit_.get()}, subject)) {
|
|
32
|
-
case napi_number:
|
|
33
|
-
|
|
34
|
-
case
|
|
35
|
-
|
|
36
|
-
// `make_property_name`.
|
|
37
|
-
return visit_(napi::value<string_tag>::from(subject), accept);
|
|
38
|
-
case napi_symbol:
|
|
39
|
-
return visit_(napi::value<symbol_tag>::from(subject), accept);
|
|
40
|
-
default:
|
|
41
|
-
std::unreachable();
|
|
31
|
+
case napi_number: return accept_as(number_tag_of<std::int32_t>{});
|
|
32
|
+
case napi_string: return accept_as(string_tag_of<char16_t>{});
|
|
33
|
+
case napi_symbol: return accept_as(symbol_tag{});
|
|
34
|
+
default: std::unreachable();
|
|
42
35
|
}
|
|
43
36
|
});
|
|
44
37
|
}
|
|
@@ -49,220 +42,296 @@ struct visit_napi_property_name {
|
|
|
49
42
|
std::reference_wrapper<Visit> visit_;
|
|
50
43
|
};
|
|
51
44
|
|
|
45
|
+
// `visit_key_literal` instantiation which creates property keys
|
|
46
|
+
template <auto Key>
|
|
47
|
+
struct visit_napi_key_literal {
|
|
48
|
+
public:
|
|
49
|
+
explicit constexpr visit_napi_key_literal(auto* /*transfer*/) {}
|
|
50
|
+
|
|
51
|
+
auto operator()(const auto& /*could_be_literally_anything*/, const auto& accept_or_visit) -> napi_value {
|
|
52
|
+
const auto make = util::overloaded{
|
|
53
|
+
[](auto& env, std::string_view subject) -> napi::value_of<string_tag_of<char>> {
|
|
54
|
+
auto* value = napi::invoke(node_api_create_property_key_latin1, napi_env{env}, subject.data(), subject.length());
|
|
55
|
+
return napi::value_of<string_tag_of<char>>::from(value);
|
|
56
|
+
},
|
|
57
|
+
[](auto& env, std::u16string_view subject) -> napi::value_of<string_tag_of<char16_t>> {
|
|
58
|
+
auto* value = napi::invoke(node_api_create_property_key_utf16, napi_env{env}, subject.data(), subject.length());
|
|
59
|
+
return napi::value_of<string_tag_of<char16_t>>::from(value);
|
|
60
|
+
},
|
|
61
|
+
[](auto& env, std::u8string_view subject) -> napi::value_of<string_tag_of<char8_t>> {
|
|
62
|
+
auto* value = napi::invoke(node_api_create_property_key_utf8, napi_env{env}, reinterpret_cast<const char*>(subject.data()), subject.length());
|
|
63
|
+
return napi::value_of<string_tag_of<char8_t>>::from(value);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
if (local_key_ == napi_value{}) {
|
|
67
|
+
constexpr auto key = util::make_consteval_string_view(Key);
|
|
68
|
+
auto& environment = accept_or_visit.environment();
|
|
69
|
+
auto storage = environment.string_table_storage(Key);
|
|
70
|
+
if (storage) {
|
|
71
|
+
auto& reference = *storage;
|
|
72
|
+
if (reference) {
|
|
73
|
+
local_key_ = reference.get(environment);
|
|
74
|
+
} else {
|
|
75
|
+
auto value = make(environment, key);
|
|
76
|
+
reference.reset(environment, value);
|
|
77
|
+
local_key_ = napi_value{value};
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
return make(environment, key);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return local_key_;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private:
|
|
87
|
+
napi_value local_key_{};
|
|
88
|
+
};
|
|
89
|
+
|
|
52
90
|
// Base napi visitor implementing all functionality. Napi doesn't give us granular information like
|
|
53
91
|
// "is this a latin1 string" and all checks must be made at once. So it's structured it great deal
|
|
54
92
|
// differently than the v8 visitor.
|
|
55
|
-
template <auto_environment Environment, class
|
|
56
|
-
struct
|
|
93
|
+
template <auto_environment Environment, class Ref>
|
|
94
|
+
struct visit_value;
|
|
57
95
|
|
|
58
96
|
template <class Meta>
|
|
59
|
-
using
|
|
97
|
+
using visit_value_with = visit_value<
|
|
60
98
|
typename Meta::visit_context_type,
|
|
61
99
|
typename Meta::accept_reference_type>;
|
|
62
100
|
|
|
63
|
-
template <auto_environment Environment, class
|
|
64
|
-
struct
|
|
65
|
-
: napi::environment_scope<Environment>,
|
|
66
|
-
reference_map_t<Target, napi_reference_map_type> {
|
|
101
|
+
template <auto_environment Environment, class Reference>
|
|
102
|
+
struct visit_value : reference_map_t<Reference, reference_map_type> {
|
|
67
103
|
public:
|
|
68
|
-
using reference_map_t<
|
|
104
|
+
using reference_map_t<Reference, reference_map_type>::lookup_or_visit;
|
|
69
105
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
equal_{env} {}
|
|
106
|
+
visit_value(auto* /*transfer*/, Environment& env) :
|
|
107
|
+
reference_map_t<Reference, reference_map_type>{env},
|
|
108
|
+
env_{env} {}
|
|
74
109
|
|
|
75
110
|
// If the private `immediate` operation is defined: this public operation will first
|
|
76
111
|
// perform a reference map lookup, then delegate to the private operation if not found.
|
|
77
|
-
template <
|
|
78
|
-
auto operator()(
|
|
112
|
+
template <class Tag, class Accept>
|
|
113
|
+
auto operator()(value_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept>
|
|
79
114
|
requires requires { immediate(subject, accept); } {
|
|
80
|
-
return lookup_or_visit(
|
|
115
|
+
return lookup_or_visit(subject, [ & ]() -> accept_target_t<Accept> {
|
|
81
116
|
return immediate(subject, accept);
|
|
82
117
|
});
|
|
83
118
|
}
|
|
84
119
|
|
|
85
120
|
// Visit operations for non-refable types.
|
|
86
121
|
template <class Accept>
|
|
87
|
-
auto operator()(
|
|
88
|
-
|
|
89
|
-
return accept_tagged(subject, accept);
|
|
122
|
+
auto operator()(value_of<null_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
123
|
+
return immediate(subject, accept);
|
|
90
124
|
}
|
|
91
125
|
|
|
92
126
|
template <class Accept>
|
|
93
|
-
auto operator()(
|
|
94
|
-
|
|
95
|
-
return accept_tagged(subject, accept);
|
|
127
|
+
auto operator()(value_of<undefined_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
128
|
+
return immediate(subject, accept);
|
|
96
129
|
}
|
|
97
130
|
|
|
98
131
|
template <class Accept>
|
|
99
|
-
auto operator()(
|
|
100
|
-
return
|
|
132
|
+
auto operator()(value_of<boolean_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
133
|
+
return immediate(subject, accept);
|
|
101
134
|
}
|
|
102
135
|
|
|
103
136
|
template <class Accept>
|
|
104
|
-
auto operator()(
|
|
105
|
-
|
|
137
|
+
auto operator()(value_of<number_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
138
|
+
if (std::bit_cast<v8::Local<v8::Number>>(subject)->IsInt32()) {
|
|
139
|
+
return immediate(value_of<number_tag_of<std::int32_t>>::from(subject), accept);
|
|
140
|
+
} else {
|
|
141
|
+
return immediate(value_of<number_tag_of<double>>::from(subject), accept);
|
|
142
|
+
}
|
|
106
143
|
}
|
|
107
144
|
|
|
108
|
-
template <class Accept>
|
|
109
|
-
auto operator()(
|
|
110
|
-
return
|
|
145
|
+
template <class Accept, class Type>
|
|
146
|
+
auto operator()(value_of<number_tag_of<Type>> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
147
|
+
return immediate(subject, accept);
|
|
111
148
|
}
|
|
112
149
|
|
|
113
150
|
// General purpose visit operation which actually performs the type check
|
|
114
151
|
template <class Accept>
|
|
115
152
|
auto operator()(napi_value subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
116
|
-
// Check known address values before the map lookup
|
|
117
|
-
// TODO: Fix it
|
|
118
|
-
// if (equal_(subject, undefined_)) {
|
|
119
|
-
// return (*this)(napi::value<undefined_tag>::from(subject), accept);
|
|
120
|
-
// } else if (equal_(subject, null_)) {
|
|
121
|
-
// return (*this)(napi::value<null_tag>::from(subject), accept);
|
|
122
|
-
// }
|
|
123
153
|
|
|
124
154
|
// Check the reference map, and lookup type via napi
|
|
125
|
-
return
|
|
126
|
-
auto
|
|
127
|
-
switch (
|
|
155
|
+
return lookup_or_visit(subject, [ & ]() -> accept_target_t<Accept> {
|
|
156
|
+
auto type_of = napi::invoke(napi_typeof, napi_env{*this}, subject);
|
|
157
|
+
switch (type_of) {
|
|
128
158
|
case napi_undefined:
|
|
129
|
-
return (*this)(
|
|
159
|
+
return (*this)(value_of<undefined_tag>::from(subject), accept);
|
|
130
160
|
case napi_null:
|
|
131
|
-
return (*this)(
|
|
161
|
+
return (*this)(value_of<null_tag>::from(subject), accept);
|
|
132
162
|
case napi_boolean:
|
|
133
|
-
return (*this)(
|
|
163
|
+
return (*this)(value_of<boolean_tag>::from(subject), accept);
|
|
134
164
|
case napi_number:
|
|
135
|
-
return (*this)(
|
|
165
|
+
return (*this)(value_of<number_tag>::from(subject), accept);
|
|
136
166
|
case napi_string:
|
|
137
|
-
return immediate(
|
|
167
|
+
return immediate(value_of<string_tag>::from(subject), accept);
|
|
138
168
|
case napi_symbol:
|
|
139
|
-
return (
|
|
169
|
+
return immediate(value_of<symbol_tag>::from(subject), accept);
|
|
140
170
|
case napi_object:
|
|
141
171
|
{
|
|
142
172
|
if (napi::invoke(napi_is_array, napi_env{*this}, subject)) {
|
|
143
|
-
return immediate(
|
|
173
|
+
return immediate(value_of<list_tag>::from(subject), accept);
|
|
144
174
|
} else if (napi::invoke(napi_is_date, napi_env{*this}, subject)) {
|
|
145
|
-
return immediate(
|
|
175
|
+
return immediate(value_of<date_tag>::from(subject), accept);
|
|
176
|
+
} else if (napi::invoke(napi_is_typedarray, napi_env{*this}, subject)) {
|
|
177
|
+
return immediate(value_of<typed_array_tag>::from(subject), accept);
|
|
178
|
+
} else if (napi::invoke(napi_is_dataview, napi_env{*this}, subject)) {
|
|
179
|
+
return immediate(value_of<data_view_tag>::from(subject), accept);
|
|
180
|
+
} else if (std::bit_cast<v8::Local<v8::Object>>(subject)->IsSharedArrayBuffer()) {
|
|
181
|
+
return immediate(value_of<shared_array_buffer_tag>::from(subject), accept);
|
|
182
|
+
} else if (napi::invoke(napi_is_arraybuffer, napi_env{*this}, subject)) {
|
|
183
|
+
return immediate(value_of<array_buffer_tag>::from(subject), accept);
|
|
146
184
|
} else if (napi::invoke(napi_is_promise, napi_env{*this}, subject)) {
|
|
147
|
-
return immediate(
|
|
185
|
+
return immediate(value_of<promise_tag>::from(subject), accept);
|
|
186
|
+
} else {
|
|
187
|
+
return immediate(value_of<dictionary_tag>::from(subject), accept);
|
|
148
188
|
}
|
|
149
|
-
return immediate(napi::value<object_tag>::from(subject), accept);
|
|
150
189
|
}
|
|
151
190
|
case napi_function:
|
|
152
|
-
return immediate(
|
|
191
|
+
return immediate(value_of<function_tag>::from(subject), accept);
|
|
153
192
|
case napi_external:
|
|
154
|
-
return immediate(
|
|
193
|
+
return immediate(value_of<external_tag>::from(subject), accept);
|
|
155
194
|
case napi_bigint:
|
|
156
|
-
return immediate(
|
|
195
|
+
return immediate(value_of<bigint_tag>::from(subject), accept);
|
|
157
196
|
}
|
|
197
|
+
std::unreachable();
|
|
158
198
|
});
|
|
159
199
|
}
|
|
160
200
|
|
|
161
|
-
//
|
|
201
|
+
// extras
|
|
202
|
+
[[nodiscard]] auto environment() const -> Environment& { return env_; }
|
|
203
|
+
explicit operator napi_env() const { return napi_env{env_.get()}; }
|
|
162
204
|
consteval static auto types(auto /*recursive*/) { return util::type_pack{}; }
|
|
163
205
|
|
|
164
206
|
private:
|
|
165
|
-
//
|
|
207
|
+
// I think this only applies to `symbol_tag`
|
|
208
|
+
template <class Accept, class Tag>
|
|
209
|
+
requires std::is_base_of_v<primitive_tag, Tag>
|
|
210
|
+
auto immediate(value_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
211
|
+
return accept_tagged(subject, accept);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// strings
|
|
215
|
+
template <class Accept>
|
|
216
|
+
auto immediate(value_of<string_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
217
|
+
if (std::bit_cast<v8::Local<v8::String>>(subject)->IsOneByte()) {
|
|
218
|
+
return accept_tagged(value_of<string_tag_of<char16_t>>::from(subject), accept);
|
|
219
|
+
} else {
|
|
220
|
+
return accept_tagged(value_of<string_tag_of<char>>::from(subject), accept);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// bigint
|
|
166
225
|
template <class Accept>
|
|
167
|
-
auto immediate(
|
|
168
|
-
return accept_tagged(
|
|
226
|
+
auto immediate(value_of<bigint_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
227
|
+
return accept_tagged(value_of<bigint_tag_of<bigint>>::from(subject), accept);
|
|
169
228
|
}
|
|
170
229
|
|
|
230
|
+
// date
|
|
171
231
|
template <class Accept>
|
|
172
|
-
auto immediate(
|
|
232
|
+
auto immediate(value_of<date_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
173
233
|
return accept_tagged(subject, accept);
|
|
174
234
|
}
|
|
175
235
|
|
|
236
|
+
// data blocks
|
|
176
237
|
template <class Accept>
|
|
177
|
-
auto immediate(
|
|
238
|
+
auto immediate(value_of<data_block_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
239
|
+
if (napi::invoke(napi_is_arraybuffer, napi_env{*this}, subject)) {
|
|
240
|
+
return immediate(value_of<array_buffer_tag>::from(subject), accept);
|
|
241
|
+
} else {
|
|
242
|
+
return immediate(value_of<shared_array_buffer_tag>::from(subject), accept);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
template <class Accept, class Tag>
|
|
247
|
+
requires std::is_base_of_v<data_block_tag, Tag>
|
|
248
|
+
auto immediate(value_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
178
249
|
return accept_tagged(subject, accept);
|
|
179
250
|
}
|
|
180
251
|
|
|
252
|
+
// array buffer views
|
|
181
253
|
template <class Accept>
|
|
182
|
-
auto immediate(
|
|
254
|
+
auto immediate(value_of<typed_array_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
255
|
+
auto bound_subject_variant = bound_value_for_typed_array::make_bound(environment(), subject);
|
|
256
|
+
if (bound_subject_variant.index() == std::variant_npos) {
|
|
257
|
+
std::unreachable();
|
|
258
|
+
} else {
|
|
259
|
+
return std::visit(
|
|
260
|
+
[ & ]<class Tag>(bound_value<Tag> value) -> accept_target_t<Accept> {
|
|
261
|
+
return accept(Tag{}, *this, value);
|
|
262
|
+
},
|
|
263
|
+
bound_subject_variant
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
template <class Accept>
|
|
269
|
+
auto immediate(value_of<data_view_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
183
270
|
return accept_tagged(subject, accept);
|
|
184
271
|
}
|
|
185
272
|
|
|
273
|
+
// externals
|
|
186
274
|
template <class Accept>
|
|
187
|
-
auto immediate(
|
|
275
|
+
auto immediate(value_of<external_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
188
276
|
return accept_tagged(subject, accept);
|
|
189
277
|
}
|
|
190
278
|
|
|
279
|
+
// promise
|
|
191
280
|
template <class Accept>
|
|
192
|
-
auto immediate(
|
|
193
|
-
return accept_tagged(
|
|
281
|
+
auto immediate(value_of<promise_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
282
|
+
return accept_tagged(subject, accept);
|
|
194
283
|
}
|
|
195
284
|
|
|
285
|
+
// function
|
|
196
286
|
template <class Accept>
|
|
197
|
-
auto immediate(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
287
|
+
auto immediate(value_of<function_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
288
|
+
return accept_tagged(subject, accept);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// array
|
|
292
|
+
template <class Accept>
|
|
293
|
+
auto immediate(value_of<list_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
294
|
+
auto target = napi::bound_value{napi_env{*this}, value_of<list_tag>::from(subject)};
|
|
295
|
+
auto visit_entry = visit_entry_pair<visit_property_name<visit_value>, visit_value&>{*this};
|
|
201
296
|
return accept(list_tag{}, visit_entry, target);
|
|
202
297
|
}
|
|
203
298
|
|
|
299
|
+
// object / record
|
|
204
300
|
template <class Accept>
|
|
205
|
-
auto immediate(
|
|
206
|
-
auto target = napi::bound_value{napi_env{*this},
|
|
207
|
-
auto visit_entry = visit_entry_pair<
|
|
301
|
+
auto immediate(value_of<dictionary_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
302
|
+
auto target = napi::bound_value{napi_env{*this}, value_of<dictionary_tag>::from(subject)};
|
|
303
|
+
auto visit_entry = visit_entry_pair<visit_property_name<visit_value>, visit_value&>{*this};
|
|
208
304
|
return accept(dictionary_tag{}, visit_entry, target);
|
|
209
305
|
}
|
|
210
306
|
|
|
211
307
|
// Convenience function which wraps in `napi::bound_value` and invokes `accept`.
|
|
212
|
-
template <
|
|
213
|
-
[[nodiscard]] auto accept_tagged(
|
|
214
|
-
return accept(Tag{}, *this, napi::bound_value{
|
|
308
|
+
template <class Tag, class Accept>
|
|
309
|
+
[[nodiscard]] auto accept_tagged(value_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
310
|
+
return accept(Tag{}, *this, napi::bound_value{environment(), subject});
|
|
215
311
|
}
|
|
216
312
|
|
|
217
|
-
|
|
218
|
-
napi_value undefined_{napi::null_value_handle};
|
|
219
|
-
napi_value null_{napi::null_value_handle};
|
|
313
|
+
std::reference_wrapper<Environment> env_;
|
|
220
314
|
};
|
|
221
315
|
|
|
222
|
-
//
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
using visit_napi_value_with<Meta>::visit_napi_value_with;
|
|
226
|
-
};
|
|
316
|
+
} // namespace js::napi
|
|
317
|
+
|
|
318
|
+
namespace js {
|
|
227
319
|
|
|
320
|
+
// Napi value visitor entry
|
|
228
321
|
template <class Meta>
|
|
229
|
-
struct visit<Meta,
|
|
230
|
-
using
|
|
322
|
+
struct visit<Meta, napi_value> : napi::visit_value_with<Meta> {
|
|
323
|
+
using napi::visit_value_with<Meta>::visit_value_with;
|
|
231
324
|
};
|
|
232
325
|
|
|
233
|
-
template <class Meta>
|
|
234
|
-
struct visit<Meta,
|
|
235
|
-
using
|
|
326
|
+
template <class Meta, class Tag>
|
|
327
|
+
struct visit<Meta, napi::value_of<Tag>> : napi::visit_value_with<Meta> {
|
|
328
|
+
using napi::visit_value_with<Meta>::visit_value_with;
|
|
236
329
|
};
|
|
237
330
|
|
|
238
331
|
// Object key maker via napi
|
|
239
332
|
template <auto Key>
|
|
240
|
-
struct visit_key_literal<Key, napi_value> :
|
|
241
|
-
|
|
242
|
-
explicit constexpr visit_key_literal(auto* /*transfer*/) {}
|
|
243
|
-
|
|
244
|
-
auto operator()(const auto& /*could_be_literally_anything*/, const auto& accept_or_visit) -> napi_value {
|
|
245
|
-
if (local_key_ == napi_value{}) {
|
|
246
|
-
auto& environment = accept_or_visit.environment();
|
|
247
|
-
auto storage = environment.string_table_storage(Key);
|
|
248
|
-
if (storage) {
|
|
249
|
-
auto& reference = *storage;
|
|
250
|
-
if (reference) {
|
|
251
|
-
local_key_ = reference.get(environment);
|
|
252
|
-
} else {
|
|
253
|
-
auto value = napi::value<string_tag>::make_property_name(environment, util::consteval_string_view{Key});
|
|
254
|
-
reference.reset(environment, value);
|
|
255
|
-
local_key_ = napi_value{value};
|
|
256
|
-
}
|
|
257
|
-
} else {
|
|
258
|
-
return napi::value<string_tag>::make_property_name(environment, util::consteval_string_view{Key});
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
return local_key_;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
private:
|
|
265
|
-
napi_value local_key_{};
|
|
333
|
+
struct visit_key_literal<Key, napi_value> : napi::visit_napi_key_literal<Key> {
|
|
334
|
+
using napi::visit_napi_key_literal<Key>::visit_napi_key_literal;
|
|
266
335
|
};
|
|
267
336
|
|
|
268
337
|
} // namespace js
|
package/value/array.cc
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
module;
|
|
2
|
-
#include <cstdint>
|
|
3
1
|
module napi_js;
|
|
4
2
|
import :api;
|
|
5
3
|
import :bound_value;
|
|
@@ -14,7 +12,7 @@ auto bound_value_for_vector::end() const -> iterator {
|
|
|
14
12
|
return {*this, size()};
|
|
15
13
|
}
|
|
16
14
|
|
|
17
|
-
auto bound_value_for_vector::size() const -> uint32_t {
|
|
15
|
+
auto bound_value_for_vector::size() const -> std::uint32_t {
|
|
18
16
|
if (size_ == 0) {
|
|
19
17
|
size_ = napi::invoke(napi_get_array_length, env(), napi_value{*this}) + 1;
|
|
20
18
|
}
|
package/value/array.h.cc
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
module;
|
|
2
|
-
#include <compare>
|
|
3
|
-
#include <cstdint>
|
|
4
1
|
export module napi_js:array;
|
|
5
|
-
import :bound_value;
|
|
6
2
|
import :object;
|
|
7
|
-
import :value_handle;
|
|
8
3
|
import auto_js;
|
|
9
|
-
import nodejs;
|
|
10
4
|
import util;
|
|
11
5
|
|
|
12
6
|
namespace js::napi {
|
|
@@ -15,21 +9,21 @@ class bound_value_for_vector : public bound_value_next<vector_tag> {
|
|
|
15
9
|
public:
|
|
16
10
|
class iterator;
|
|
17
11
|
using bound_value_next<vector_tag>::bound_value_next;
|
|
18
|
-
using value_type =
|
|
12
|
+
using value_type = value_of<value_tag>;
|
|
19
13
|
|
|
20
14
|
[[nodiscard]] auto begin() const -> iterator;
|
|
21
15
|
[[nodiscard]] auto end() const -> iterator;
|
|
22
|
-
[[nodiscard]] auto size() const -> uint32_t;
|
|
16
|
+
[[nodiscard]] auto size() const -> std::uint32_t;
|
|
23
17
|
|
|
24
18
|
private:
|
|
25
|
-
mutable uint32_t size_{};
|
|
19
|
+
mutable std::uint32_t size_{};
|
|
26
20
|
};
|
|
27
21
|
|
|
28
|
-
class bound_value_for_vector::iterator : public util::random_access_iterator_facade<int32_t, int64_t> {
|
|
22
|
+
class bound_value_for_vector::iterator : public util::random_access_iterator_facade<std::int32_t, std::int64_t> {
|
|
29
23
|
public:
|
|
30
24
|
using arithmetic_facade::operator+;
|
|
31
25
|
using difference_type = arithmetic_facade::difference_type;
|
|
32
|
-
using size_type = uint32_t;
|
|
26
|
+
using size_type = std::uint32_t;
|
|
33
27
|
using value_type = bound_value_for_vector::value_type;
|
|
34
28
|
|
|
35
29
|
iterator() = default;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
module napi_js;
|
|
2
|
+
import :api;
|
|
3
|
+
import :array_buffer;
|
|
4
|
+
import std;
|
|
5
|
+
import v8;
|
|
6
|
+
|
|
7
|
+
namespace js::napi {
|
|
8
|
+
|
|
9
|
+
// `bound_value_for_array_buffer`
|
|
10
|
+
bound_value_for_array_buffer::operator js::array_buffer() const {
|
|
11
|
+
return js::array_buffer{std::span<std::byte>{*this}};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
bound_value_for_array_buffer::operator std::span<std::byte>() const {
|
|
15
|
+
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
|
16
|
+
void* bytes;
|
|
17
|
+
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
|
18
|
+
std::size_t byte_length;
|
|
19
|
+
napi::invoke0(napi_get_arraybuffer_info, env(), napi_value{*this}, &bytes, &byte_length);
|
|
20
|
+
return std::span<std::byte>{reinterpret_cast<std::byte*>(bytes), byte_length};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// `bound_value_for_shared_array_buffer`
|
|
24
|
+
bound_value_for_shared_array_buffer::operator js::shared_array_buffer() const {
|
|
25
|
+
auto local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{*this});
|
|
26
|
+
auto backing_store = local->GetBackingStore();
|
|
27
|
+
auto* data = reinterpret_cast<std::byte*>(backing_store->Data());
|
|
28
|
+
auto data_shared_ptr = std::shared_ptr<js::shared_array_buffer::array_type>{std::move(backing_store), data};
|
|
29
|
+
return js::shared_array_buffer{local->ByteLength(), std::move(data_shared_ptr)};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
bound_value_for_shared_array_buffer::operator std::span<std::byte>() const {
|
|
33
|
+
auto local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{*this});
|
|
34
|
+
return std::span<std::byte>{reinterpret_cast<std::byte*>(local->Data()), local->ByteLength()};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// `value_for_typed_array`
|
|
38
|
+
auto value_for_typed_array::make(const environment& env, napi_typedarray_type type_tag, value_of<array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> value_of<typed_array_tag> {
|
|
39
|
+
return value_of<typed_array_tag>::from(napi::invoke(napi_create_typedarray, napi_env{env}, type_tag, length, napi_value{buffer}, byte_offset));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// `bound_value_for_typed_array`
|
|
43
|
+
auto bound_value_for_typed_array::make_bound(const environment& env, value_of<typed_array_tag> typed_array) -> any_bound_typed_array {
|
|
44
|
+
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
|
45
|
+
napi_typedarray_type type_tag;
|
|
46
|
+
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
|
47
|
+
napi_value array_buffer;
|
|
48
|
+
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
|
49
|
+
std::size_t length;
|
|
50
|
+
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
|
51
|
+
std::size_t byte_offset;
|
|
52
|
+
napi::invoke0(napi_get_typedarray_info, env, napi_value{typed_array}, &type_tag, &length, nullptr, &array_buffer, &byte_offset);
|
|
53
|
+
const auto make = [ & ]<class Tag>(Tag /*tag*/) -> any_bound_typed_array {
|
|
54
|
+
return bound_value<Tag>{env, value_of<Tag>::from(typed_array), std::tuple{value_of<data_block_tag>::from(array_buffer), byte_offset, length}};
|
|
55
|
+
};
|
|
56
|
+
switch (type_tag) {
|
|
57
|
+
case napi_bigint64_array: return make(typed_array_tag_of<std::int64_t>{});
|
|
58
|
+
case napi_biguint64_array: return make(typed_array_tag_of<std::uint64_t>{});
|
|
59
|
+
case napi_float16_array: throw std::logic_error{"unsupported"};
|
|
60
|
+
case napi_float32_array: return make(typed_array_tag_of<float>{});
|
|
61
|
+
case napi_float64_array: return make(typed_array_tag_of<double>{});
|
|
62
|
+
case napi_int16_array: return make(typed_array_tag_of<std::int16_t>{});
|
|
63
|
+
case napi_int32_array: return make(typed_array_tag_of<std::int32_t>{});
|
|
64
|
+
case napi_int8_array: return make(typed_array_tag_of<std::int8_t>{});
|
|
65
|
+
case napi_uint16_array: return make(typed_array_tag_of<std::uint16_t>{});
|
|
66
|
+
case napi_uint32_array: return make(typed_array_tag_of<std::uint32_t>{});
|
|
67
|
+
case napi_uint8_array: return make(typed_array_tag_of<std::uint8_t>{});
|
|
68
|
+
case napi_uint8_clamped_array: return make(typed_array_tag_of<std::byte>{});
|
|
69
|
+
}
|
|
70
|
+
std::unreachable();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// `value_for_data_view`
|
|
74
|
+
auto value_for_data_view::make(const environment& env, value_of<data_block_tag> buffer, std::size_t byte_offset, std::size_t length) -> value_of<data_view_tag> {
|
|
75
|
+
if (napi::invoke(napi_is_arraybuffer, napi_env{env}, buffer)) {
|
|
76
|
+
return make(env, value_of<array_buffer_tag>::from(buffer), byte_offset, length);
|
|
77
|
+
} else {
|
|
78
|
+
return make(env, value_of<shared_array_buffer_tag>::from(buffer), byte_offset, length);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
auto value_for_data_view::make(const environment& env, value_of<array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> value_of<data_view_tag> {
|
|
83
|
+
return value_of<data_view_tag>::from(napi::invoke(napi_create_dataview, napi_env{env}, length, napi_value{buffer}, byte_offset));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
auto value_for_data_view::make(const environment& /*env*/, value_of<shared_array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> value_of<data_view_tag> {
|
|
87
|
+
auto buffer_local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{buffer});
|
|
88
|
+
auto view_local = v8::DataView::New(buffer_local, byte_offset, length);
|
|
89
|
+
return value_of<data_view_tag>::from(std::bit_cast<napi_value>(view_local));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// `bound_value_for_data_view`
|
|
93
|
+
bound_value_for_data_view::bound_value_for_data_view(napi_env env, value_of<data_view_tag> data_view) :
|
|
94
|
+
bound_value_next{
|
|
95
|
+
env,
|
|
96
|
+
data_view,
|
|
97
|
+
[ & ] -> auto {
|
|
98
|
+
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
|
99
|
+
napi_value array_buffer;
|
|
100
|
+
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
|
101
|
+
std::size_t length;
|
|
102
|
+
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
|
103
|
+
std::size_t byte_offset;
|
|
104
|
+
napi::invoke0(napi_get_dataview_info, env, napi_value{data_view}, &length, nullptr, &array_buffer, &byte_offset);
|
|
105
|
+
return std::tuple{value_of<data_block_tag>::from(array_buffer), byte_offset, length};
|
|
106
|
+
}(),
|
|
107
|
+
} {}
|
|
108
|
+
|
|
109
|
+
} // namespace js::napi
|