@auto_js/napi 0.0.1 → 0.0.4

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.
Files changed (51) hide show
  1. package/CMakeLists.txt +10 -4
  2. package/README.md +30 -3
  3. package/_module.cc +12 -10
  4. package/api/api.cc +8 -7
  5. package/api/callback_info.cc +1 -7
  6. package/api/finalizer.cc +1 -4
  7. package/api/invoke.cc +4 -9
  8. package/api/uv_dlib.cc +27 -0
  9. package/api/uv_dlib.h.cc +21 -0
  10. package/api/uv_handle.cc +9 -9
  11. package/api/uv_scheduler.cc +11 -17
  12. package/api/uv_scheduler.h.cc +3 -6
  13. package/handle/bound_value.cc +4 -7
  14. package/handle/reference.cc +9 -5
  15. package/handle/remote.cc +11 -17
  16. package/handle/types.cc +61 -46
  17. package/handle/value.cc +12 -14
  18. package/package.json +7 -6
  19. package/support/callback.cc +7 -19
  20. package/support/callback_storage.cc +4 -9
  21. package/support/class_template_storage.cc +4 -6
  22. package/support/container.cc +9 -10
  23. package/support/environment.cc +32 -20
  24. package/support/environment.h.cc +8 -18
  25. package/support/environment_fwd.cc +1 -2
  26. package/support/error_scope.cc +0 -2
  27. package/support/initialize.h.cc +2 -5
  28. package/support/promise.cc +3 -10
  29. package/support/string_table.cc +3 -5
  30. package/support/utility.cc +54 -28
  31. package/transfer/accept.cc +131 -327
  32. package/transfer/accept.h.cc +390 -0
  33. package/transfer/visit.cc +201 -132
  34. package/value/array.cc +1 -3
  35. package/value/array.h.cc +5 -11
  36. package/value/array_buffer.cc +109 -0
  37. package/value/array_buffer.h.cc +150 -0
  38. package/value/class.cc +12 -21
  39. package/value/class.h.cc +5 -10
  40. package/value/external.cc +6 -10
  41. package/value/function.cc +5 -12
  42. package/value/function.h.cc +2 -9
  43. package/value/object.cc +2 -6
  44. package/value/object.h.cc +7 -15
  45. package/value/primitive.cc +12 -81
  46. package/value/primitive.h.cc +6 -64
  47. package/value/record.cc +38 -0
  48. package/value/record.h.cc +39 -0
  49. package/value/value.cc +8 -8
  50. package/value/dictionary.cc +0 -33
  51. 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 napi_reference_map_type {
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 visit_napi_property_name {
19
+ struct visit_property_name {
25
20
  public:
26
- explicit visit_napi_property_name(Visit& visit) : visit_{visit} {}
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(accept, subject, [ & ]() -> accept_target_t<Accept> {
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
- return visit_(napi::value<number_tag>::from(subject), accept);
34
- case napi_string:
35
- // TODO: This looks up in the reference map twice. This should actually use
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 Target>
56
- struct visit_napi_value;
93
+ template <auto_environment Environment, class Ref>
94
+ struct visit_value;
57
95
 
58
96
  template <class Meta>
59
- using visit_napi_value_with = visit_napi_value<
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 Target>
64
- struct visit_napi_value
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<Target, napi_reference_map_type>::lookup_or_visit;
104
+ using reference_map_t<Reference, reference_map_type>::lookup_or_visit;
69
105
 
70
- visit_napi_value(auto* /*transfer*/, Environment& env) :
71
- napi::environment_scope<Environment>{env},
72
- reference_map_t<Target, napi_reference_map_type>{env},
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 <auto_tag Tag, class Accept>
78
- auto operator()(value<Tag> subject, const Accept& accept) -> accept_target_t<Accept>
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(accept, subject, [ & ]() -> accept_target_t<Accept> {
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()(value<null_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
88
- null_ = subject;
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()(value<undefined_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
94
- undefined_ = subject;
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()(value<boolean_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
100
- return accept_tagged(subject, accept);
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()(value<number_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
105
- return accept_tagged(napi::value<number_tag_of<double>>::from(subject), accept);
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()(value<symbol_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
110
- return accept_tagged(subject, accept);
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 this->lookup_or_visit(accept, subject, [ & ]() -> accept_target_t<Accept> {
126
- auto typeof = napi::invoke(napi_typeof, napi_env{*this}, subject);
127
- switch (typeof) {
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)(napi::value<undefined_tag>::from(subject), accept);
159
+ return (*this)(value_of<undefined_tag>::from(subject), accept);
130
160
  case napi_null:
131
- return (*this)(napi::value<null_tag>::from(subject), accept);
161
+ return (*this)(value_of<null_tag>::from(subject), accept);
132
162
  case napi_boolean:
133
- return (*this)(napi::value<boolean_tag>::from(subject), accept);
163
+ return (*this)(value_of<boolean_tag>::from(subject), accept);
134
164
  case napi_number:
135
- return (*this)(napi::value<number_tag>::from(subject), accept);
165
+ return (*this)(value_of<number_tag>::from(subject), accept);
136
166
  case napi_string:
137
- return immediate(napi::value<string_tag>::from(subject), accept);
167
+ return immediate(value_of<string_tag>::from(subject), accept);
138
168
  case napi_symbol:
139
- return (*this)(napi::value<symbol_tag>::from(subject), accept);
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(napi::value<list_tag>::from(subject), accept);
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(napi::value<date_tag>::from(subject), accept);
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(napi::value<promise_tag>::from(subject), accept);
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(napi::value<function_tag>::from(subject), accept);
191
+ return immediate(value_of<function_tag>::from(subject), accept);
153
192
  case napi_external:
154
- return immediate(napi::value<external_tag>::from(subject), accept);
193
+ return immediate(value_of<external_tag>::from(subject), accept);
155
194
  case napi_bigint:
156
- return immediate(napi::value<bigint_tag>::from(subject), accept);
195
+ return immediate(value_of<bigint_tag>::from(subject), accept);
157
196
  }
197
+ std::unreachable();
158
198
  });
159
199
  }
160
200
 
161
- // no required types
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
- // Private visit operations for refable types
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(value<string_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
168
- return accept_tagged(napi::value<string_tag_of<char16_t>>::from(subject), accept);
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(value<date_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
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(value<promise_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
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(value<external_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
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(value<function_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
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(value<bigint_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
193
- return accept_tagged(napi::value<bigint_tag_of<bigint>>::from(subject), accept);
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(value<list_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
198
- // nb: It is intentional that `dictionary_tag` is bound. It handles sparse arrays.
199
- auto target = napi::bound_value{napi_env{*this}, napi::value<dictionary_tag>::from(subject)};
200
- auto visit_entry = visit_entry_pair<visit_napi_property_name<visit_napi_value>, visit_napi_value&>{*this};
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(value<object_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
206
- auto target = napi::bound_value{napi_env{*this}, napi::value<dictionary_tag>::from(subject)};
207
- auto visit_entry = visit_entry_pair<visit_napi_property_name<visit_napi_value>, visit_napi_value&>{*this};
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 <auto_tag Tag, class Accept>
213
- [[nodiscard]] auto accept_tagged(value<Tag> subject, const Accept& accept) -> accept_target_t<Accept> {
214
- return accept(Tag{}, *this, napi::bound_value{napi_env{*this}, subject});
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
- napi::address_equal equal_;
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
- // Napi value visitor entry
223
- template <class Meta>
224
- struct visit<Meta, napi_value> : visit_napi_value_with<Meta> {
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, value<value_tag>> : visit_napi_value_with<Meta> {
230
- using visit_napi_value_with<Meta>::visit_napi_value_with;
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, value<object_tag>> : visit_napi_value_with<Meta> {
235
- using visit_napi_value_with<Meta>::visit_napi_value_with;
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> : util::non_moveable {
241
- public:
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 = value<value_tag>;
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