@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
@@ -0,0 +1,390 @@
1
+ export module napi_js:accept;
2
+ import :container;
3
+ import :value;
4
+ import std;
5
+ import util;
6
+
7
+ namespace js::napi {
8
+
9
+ // napi reference acceptor
10
+ struct reaccept_napi_value {
11
+ using reference_type = napi_value;
12
+
13
+ constexpr auto operator()(std::type_identity<napi_value> /*type*/, napi_value value) const -> napi_value {
14
+ return value;
15
+ }
16
+
17
+ template <class Tag>
18
+ constexpr auto operator()(std::type_identity<value_of<Tag>> /*type*/, napi_value value) const -> value_of<Tag> {
19
+ return value_of<Tag>::from(value);
20
+ }
21
+ };
22
+
23
+ // Napi acceptor which does not need specialized environment type
24
+ struct accept_basic_napi_value {
25
+ public:
26
+ explicit accept_basic_napi_value(auto* /*transfer*/, auto& env) : env_{env} {}
27
+
28
+ // Declare reference provider
29
+ using accept_reference_type = reaccept_napi_value;
30
+
31
+ // undefined & null
32
+ auto operator()(undefined_tag tag, visit_holder visit, std::monostate subject) const -> value_of<undefined_tag>;
33
+ auto operator()(undefined_tag tag, visit_holder visit, const auto& /*subject*/) const -> value_of<undefined_tag> {
34
+ return (*this)(tag, visit, std::monostate{});
35
+ }
36
+
37
+ auto operator()(null_tag tag, visit_holder visit, std::nullptr_t subject) const -> value_of<null_tag>;
38
+ auto operator()(null_tag tag, visit_holder visit, const auto& /*subject*/) const -> value_of<null_tag> {
39
+ return (*this)(tag, visit, nullptr);
40
+ }
41
+
42
+ // boolean
43
+ auto operator()(boolean_tag tag, visit_holder visit, bool subject) const -> value_of<boolean_tag>;
44
+
45
+ // number
46
+ auto operator()(number_tag_of<double> tag, visit_holder visit, double subject) const -> value_of<number_tag_of<double>>;
47
+ auto operator()(number_tag_of<std::int32_t> tag, visit_holder visit, std::int32_t subject) const -> value_of<number_tag_of<std::int32_t>>;
48
+ auto operator()(number_tag_of<std::uint32_t> tag, visit_holder visit, std::uint32_t subject) const -> value_of<number_tag_of<std::uint32_t>>;
49
+
50
+ auto operator()(number_tag /*tag*/, visit_holder visit, auto&& subject) const -> value_of<number_tag> {
51
+ return (*this)(number_tag_of<double>{}, visit, double{std::forward<decltype(subject)>(subject)});
52
+ }
53
+
54
+ template <class Type>
55
+ auto operator()(number_tag_of<Type> tag, visit_holder visit, auto&& subject) const -> value_of<number_tag_of<Type>> {
56
+ return (*this)(tag, visit, Type{std::forward<decltype(subject)>(subject)});
57
+ }
58
+
59
+ // string
60
+ auto operator()(string_tag_of<char> tag, visit_holder visit, std::string_view subject) const
61
+ -> js::referenceable_value<value_of<string_tag_of<char>>>;
62
+ auto operator()(string_tag_of<char8_t> tag, visit_holder visit, std::u8string_view subject) const
63
+ -> js::referenceable_value<value_of<string_tag_of<char8_t>>>;
64
+ auto operator()(string_tag_of<char16_t> tag, visit_holder visit, std::u16string_view subject) const
65
+ -> js::referenceable_value<value_of<string_tag_of<char16_t>>>;
66
+
67
+ auto operator()(string_tag /*tag*/, visit_holder visit, auto&& subject) const
68
+ -> js::referenceable_value<value_of<string_tag>> {
69
+ auto value = (*this)(string_tag_of<char16_t>{}, visit, std::u16string_view{std::forward<decltype(subject)>(subject)});
70
+ return js::referenceable_value{value_of<string_tag>{*value}};
71
+ }
72
+
73
+ template <class Char>
74
+ auto operator()(string_tag_of<Char> tag, visit_holder visit, std::convertible_to<std::basic_string_view<Char>> auto&& subject) const
75
+ -> js::referenceable_value<value_of<string_tag_of<Char>>> {
76
+ return (*this)(tag, visit, std::basic_string_view<Char>{std::forward<decltype(subject)>(subject)});
77
+ }
78
+
79
+ template <class Char>
80
+ auto operator()(string_tag_of<Char> tag, visit_holder visit, auto&& subject) const
81
+ -> js::referenceable_value<value_of<string_tag_of<Char>>> {
82
+ return (*this)(tag, visit, std::basic_string<Char>{std::forward<decltype(subject)>(subject)});
83
+ }
84
+
85
+ // bigint
86
+ auto operator()(bigint_tag_of<std::int64_t> tag, visit_holder visit, std::int64_t subject) const
87
+ -> js::referenceable_value<value_of<bigint_tag_of<std::int64_t>>>;
88
+ auto operator()(bigint_tag_of<std::uint64_t> tag, visit_holder visit, std::uint64_t subject) const
89
+ -> js::referenceable_value<value_of<bigint_tag_of<std::uint64_t>>>;
90
+ auto operator()(bigint_tag_of<js::bigint> tag, visit_holder visit, const js::bigint& subject) const
91
+ -> js::referenceable_value<value_of<bigint_tag_of<js::bigint>>>;
92
+ auto operator()(bigint_tag_of<js::bigint> tag, visit_holder visit, js::bigint&& subject) const
93
+ -> js::referenceable_value<value_of<bigint_tag_of<js::bigint>>>;
94
+
95
+ auto operator()(bigint_tag /*tag*/, visit_holder visit, auto&& subject) const
96
+ -> js::referenceable_value<value_of<bigint_tag>> {
97
+ auto value = (*this)(bigint_tag_of<js::bigint>{}, visit, js::bigint{std::forward<decltype(subject)>(subject)});
98
+ return js::referenceable_value{value_of<bigint_tag>{*value}};
99
+ }
100
+
101
+ template <class Type>
102
+ auto operator()(bigint_tag_of<Type> tag, visit_holder visit, auto&& subject) const
103
+ -> js::referenceable_value<value_of<bigint_tag_of<Type>>> {
104
+ return (*this)(tag, visit, Type{std::forward<decltype(subject)>(subject)});
105
+ }
106
+
107
+ // date
108
+ auto operator()(date_tag tag, visit_holder /*visit*/, js_clock::time_point subject) const
109
+ -> js::referenceable_value<value_of<date_tag>>;
110
+
111
+ // error
112
+ auto operator()(error_tag /*tag*/, visit_holder visit, const js::error_value& subject) const
113
+ -> js::referenceable_value<value_of<error_tag>>;
114
+
115
+ auto operator()(error_tag tag, visit_holder visit, const auto& subject) const
116
+ -> js::referenceable_value<value_of<error_tag>> {
117
+ return (*this)(tag, visit, js::error_value{subject});
118
+ }
119
+
120
+ // data blocks (array buffer, shared array buffer)
121
+ auto operator()(array_buffer_tag tag, visit_holder visit, const js::array_buffer& subject) const
122
+ -> js::referenceable_value<value_of<array_buffer_tag>>;
123
+ auto operator()(shared_array_buffer_tag tag, visit_holder visit, js::shared_array_buffer&& subject) const
124
+ -> js::referenceable_value<value_of<shared_array_buffer_tag>>;
125
+ auto operator()(shared_array_buffer_tag tag, visit_holder visit, const js::shared_array_buffer& subject) const
126
+ -> js::referenceable_value<value_of<shared_array_buffer_tag>>;
127
+
128
+ // typed arrays & data view
129
+ template <std::convertible_to<array_buffer_view_tag> Tag>
130
+ auto operator()(this const auto& self, Tag /*tag*/, auto& visit, auto&& subject)
131
+ -> js::referenceable_value<value_of<Tag>> {
132
+ auto byte_offset = subject.byte_offset();
133
+ auto length = subject.size();
134
+ // TODO: We accept the nested `buffer` property as a `data_block` which means `make` needs to
135
+ // invoke `is_arraybuffer` on it again even though we knew what it was a moment ago.
136
+ auto buffer = value_of<data_block_tag>::from(visit(std::forward<decltype(subject)>(subject).buffer(), self));
137
+ return js::referenceable_value{value_of<Tag>::make(self.environment(), buffer, byte_offset, length)};
138
+ }
139
+
140
+ // extras
141
+ [[nodiscard]] auto environment() const -> environment& { return env_; }
142
+ explicit operator napi_env() const { return napi_env{env_.get()}; }
143
+
144
+ private:
145
+ std::reference_wrapper<napi::environment> env_;
146
+ };
147
+
148
+ // Generic napi acceptor which accepts all value types.
149
+ template <class Environment>
150
+ struct accept_napi_value;
151
+
152
+ template <class Meta>
153
+ using accept_napi_value_with = accept_napi_value<typename Meta::accept_context_type>;
154
+
155
+ template <class Environment>
156
+ struct accept_napi_value : accept_basic_napi_value {
157
+ public:
158
+ explicit accept_napi_value(auto* transfer, auto& env) :
159
+ accept_basic_napi_value{transfer, env} {}
160
+ using accept_basic_napi_value::operator();
161
+
162
+ // function
163
+ template <class Callback>
164
+ auto operator()(function_prototype_tag /*tag*/, visit_holder /*visit*/, js::free_function<Callback> subject) const -> value_of<function_tag> {
165
+ return value_of<function_tag>::make(environment(), std::forward<decltype(subject)>(subject));
166
+ }
167
+
168
+ // vectors
169
+ auto operator()(this const auto& self, vector_tag /*tag*/, auto& visit, auto&& subject)
170
+ -> js::deferred_receiver<value_of<vector_tag>, decltype(self), decltype(visit), decltype(subject)> {
171
+ return {
172
+ value_of<vector_tag>::from(napi::invoke(napi_create_array_with_length, napi_env{self}, subject.size())),
173
+ std::forward_as_tuple(self, visit, std::forward<decltype(subject)>(subject)),
174
+ [](value_of<vector_tag> array, auto& self, auto& visit, auto /*&&*/ subject) -> void {
175
+ int ii = 0;
176
+ auto&& range = util::into_range(std::forward<decltype(subject)>(subject));
177
+ for (auto&& subject : util::forward_range(std::forward<decltype(range)>(range))) {
178
+ auto* element = napi_value{visit(std::forward<decltype(subject)>(subject), self)};
179
+ napi::invoke0(napi_set_element, napi_env{self}, napi_value{array}, ii++, element);
180
+ }
181
+ },
182
+ };
183
+ }
184
+
185
+ template <std::size_t Size>
186
+ auto operator()(this const auto& self, tuple_tag<Size> /*tag*/, auto& visit, auto&& subject)
187
+ -> js::deferred_receiver<value_of<vector_tag>, decltype(self), decltype(visit), decltype(subject)> {
188
+ return {
189
+ value_of<vector_tag>::from(napi::invoke(napi_create_array_with_length, napi_env{self}, Size)),
190
+ std::forward_as_tuple(self, visit, std::forward<decltype(subject)>(subject)),
191
+ [](value_of<vector_tag> array, auto& self, auto& visit, auto /*&&*/ tuple) -> void {
192
+ const auto [... indices ] = util::sequence<Size>;
193
+ (..., [ & ]() -> void {
194
+ // nb: This is forwarded to *each* visitor. The visitor should be aware and only lvalue
195
+ // reference members one at a time.
196
+ auto* element = napi_value{visit(indices, std::forward<decltype(tuple)>(tuple), self)};
197
+ napi::invoke0(napi_set_element, napi_env{self}, napi_value{array}, indices, element);
198
+ }());
199
+ }
200
+ };
201
+ }
202
+
203
+ // arrays & dictionaries
204
+ auto operator()(this const auto& self, list_tag /*tag*/, auto& visit, auto&& subject)
205
+ -> js::deferred_receiver<value_of<list_tag>, decltype(self), decltype(visit), decltype(subject)> {
206
+ return {
207
+ value_of<list_tag>::from(napi::invoke(napi_create_array, napi_env{self})),
208
+ std::forward_as_tuple(self, visit, std::forward<decltype(subject)>(subject)),
209
+ [](value_of<list_tag> array, auto& self, auto& visit, auto /*&&*/ subject) -> void {
210
+ self.accept_entry_pair_vector(visit, array, std::forward<decltype(subject)>(subject));
211
+ }
212
+ };
213
+ }
214
+
215
+ auto operator()(this const auto& self, dictionary_tag /*tag*/, auto& visit, auto&& subject)
216
+ -> js::deferred_receiver<value_of<dictionary_tag>, decltype(self), decltype(visit), decltype(subject)> {
217
+ return {
218
+ value_of<dictionary_tag>::from(napi::invoke(napi_create_object, napi_env{self})),
219
+ std::forward_as_tuple(self, visit, std::forward<decltype(subject)>(subject)),
220
+ [](value_of<dictionary_tag> object, auto& self, auto& visit, auto /*&&*/ subject) -> void {
221
+ self.accept_entry_pair_vector(visit, object, std::forward<decltype(subject)>(subject));
222
+ }
223
+ };
224
+ }
225
+
226
+ auto accept_entry_pair_vector(this const auto& self, auto& visit, value_of<object_tag> target, auto&& subject) -> void {
227
+ std::vector<napi_property_descriptor> properties;
228
+ auto&& range = util::into_range(std::forward<decltype(subject)>(subject));
229
+ properties.reserve(std::size(range));
230
+ for (auto&& [ key, value ] : util::forward_range(std::forward<decltype(range)>(range))) {
231
+ auto* name = napi_value{visit.first(std::forward<decltype(key)>(key), self)};
232
+ properties.emplace_back(napi_property_descriptor{
233
+ .utf8name{},
234
+ // TODO: `napi_define_properties` only works with string keys but the nested acceptor will
235
+ // accept indexed properties as numeric napi values. `visit.first` should be invoked
236
+ // against something that maybe resolves to `std::variant<int32_t, value_of<name_tag>>`.
237
+ .name = napi::invoke(napi_coerce_to_string, napi_env{self}, name),
238
+
239
+ .method{},
240
+ .getter{},
241
+ .setter{},
242
+ .value = napi_value{visit.second(std::forward<decltype(value)>(value), self)},
243
+
244
+ // NOLINTNEXTLINE(hicpp-signed-bitwise)
245
+ .attributes = static_cast<napi_property_attributes>(napi_writable | napi_enumerable | napi_configurable),
246
+ .data{},
247
+ });
248
+ }
249
+ napi::invoke0(napi_define_properties, napi_env{self}, napi_value{target}, properties.size(), properties.data());
250
+ }
251
+
252
+ // structs
253
+ template <std::size_t Size>
254
+ auto operator()(this const auto& self, struct_tag<Size> /*tag*/, auto& visit, auto&& subject)
255
+ -> js::deferred_receiver<value_of<dictionary_tag>, decltype(self), decltype(visit), decltype(subject)> {
256
+ return {
257
+ value_of<dictionary_tag>::from(napi::invoke(napi_create_object, napi_env{self})),
258
+ std::forward_as_tuple(self, visit, std::forward<decltype(subject)>(subject)),
259
+ [](value_of<dictionary_tag> object, auto& self, auto& visit, auto /*&&*/ subject) -> void {
260
+ self.template accept_entry_pair_struct<Size>(visit, object, std::forward<decltype(subject)>(subject));
261
+ }
262
+ };
263
+ }
264
+
265
+ template <std::size_t Size>
266
+ auto accept_entry_pair_struct(this const auto& self, auto& visit, value_of<object_tag> target, auto&& subject) -> void {
267
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
268
+ std::array<napi_property_descriptor, Size> properties;
269
+ const auto [... indices ] = util::sequence<Size>;
270
+ (..., [ & ]() -> void {
271
+ // nb: This is forwarded to *each* visitor. The visitor should be aware and only lvalue
272
+ // reference members one at a time.
273
+ auto accept_entry = accept_entry_pair<decltype(self), decltype(self)>{self};
274
+ auto entry = visit(std::integral_constant<std::size_t, indices>{}, std::forward<decltype(subject)>(subject), accept_entry);
275
+ // NOLINTNEXTLINE(modernize-type-traits)
276
+ properties.at(indices) = {
277
+ .utf8name{},
278
+ .name = entry.first,
279
+
280
+ .method{},
281
+ .getter{},
282
+ .setter{},
283
+ .value = entry.second,
284
+
285
+ // NOLINTNEXTLINE(hicpp-signed-bitwise)
286
+ .attributes = static_cast<napi_property_attributes>(napi_writable | napi_enumerable | napi_configurable),
287
+ .data{},
288
+ };
289
+ }());
290
+ napi::invoke0(napi_define_properties, napi_env{self}, napi_value{target}, properties.size(), properties.data());
291
+ }
292
+
293
+ // extras
294
+ [[nodiscard]] auto environment() const -> Environment& {
295
+ return static_cast<Environment&>(accept_basic_napi_value::environment());
296
+ }
297
+
298
+ consteval static auto types(auto /*recursive*/) { return util::type_pack{}; }
299
+ };
300
+
301
+ // `value_of<object_tag>{}.assign(...)` implementation
302
+ struct object_assign_delegate {
303
+ public:
304
+ explicit object_assign_delegate(value_of<object_tag> object) : object_{object} {}
305
+ auto operator*() const { return object_; }
306
+
307
+ private:
308
+ value_of<object_tag> object_;
309
+ };
310
+
311
+ auto value_for_object::assign(this value_of<object_tag> self, auto_environment auto& env, auto source) -> void {
312
+ js::transfer_in<object_assign_delegate>(std::move(source), env, object_assign_delegate{self});
313
+ }
314
+
315
+ } // namespace js::napi
316
+
317
+ namespace js {
318
+
319
+ // Plain napi_value acceptor
320
+ template <>
321
+ struct accept_property_subject<napi_value> : std::type_identity<napi_value> {};
322
+
323
+ template <class Meta>
324
+ struct accept<Meta, napi_value> : napi::accept_napi_value_with<Meta> {
325
+ using accept_type = napi::accept_napi_value_with<Meta>;
326
+ using accept_type::accept_type;
327
+ };
328
+
329
+ // Tagged `value_of<T>` acceptor
330
+ template <>
331
+ struct accept_property_subject<napi::value_of<value_tag>> : std::type_identity<napi_value> {};
332
+
333
+ template <class Meta, class Tag>
334
+ struct accept<Meta, napi::value_of<Tag>> : napi::accept_napi_value_with<Meta> {
335
+ using accept_type = napi::accept_napi_value_with<Meta>;
336
+ using accept_type::accept_type;
337
+ };
338
+
339
+ // Forwarded `value_of<T>` acceptor
340
+ template <class Tag>
341
+ struct accept<void, js::forward<napi::value_of<Tag>, Tag>> {
342
+ auto operator()(Tag /*tag*/, visit_holder /*visit*/, napi::value_of<Tag> subject) const -> js::forward<napi::value_of<Tag>, Tag> {
343
+ return js::forward{napi::value_of<Tag>{subject}, Tag{}};
344
+ }
345
+
346
+ consteval static auto types(auto /*recursive*/) { return util::type_pack{}; }
347
+ };
348
+
349
+ // Object key lookup via napi
350
+ template <class Meta, auto Key, class Type>
351
+ struct accept_property_value<Meta, Key, Type, napi_value> {
352
+ public:
353
+ explicit constexpr accept_property_value(auto* transfer) :
354
+ first{transfer},
355
+ second{transfer} {}
356
+
357
+ auto operator()(dictionary_tag /*tag*/, auto& visit, const auto& subject) const -> Type {
358
+ if (auto local = first(std::type_identity<void>{}, visit.first); subject.has(local)) {
359
+ return visit.second(subject.get(local), second);
360
+ } else {
361
+ return second(undefined_in_tag{}, visit.second, std::monostate{});
362
+ }
363
+ }
364
+
365
+ private:
366
+ mutable visit_key_literal<Key, napi_value> first;
367
+ accept_value<Meta, Type> second;
368
+ };
369
+
370
+ template <class Meta>
371
+ struct accept<Meta, napi::object_assign_delegate> {
372
+ public:
373
+ accept(auto* transfer, auto& env, napi::object_assign_delegate object) :
374
+ accept_{transfer, env},
375
+ object_{object} {}
376
+
377
+ template <std::size_t Size>
378
+ auto operator()(this const auto& self, tuple_tag<Size> /*tag*/, auto& visit, auto&& subject) -> napi::object_assign_delegate {
379
+ self.accept_.template accept_entry_pair_struct<Size>(visit, *self.object_, std::forward<decltype(subject)>(subject));
380
+ return self.object_;
381
+ }
382
+
383
+ consteval static auto types(auto recursive) { return accept<Meta, napi_value>::types(recursive); }
384
+
385
+ private:
386
+ accept_value<Meta, napi_value> accept_;
387
+ napi::object_assign_delegate object_;
388
+ };
389
+
390
+ } // namespace js