@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
@@ -1,9 +1,7 @@
1
- module;
2
- #include <string> // IWYU pragma: keep
3
- #include <type_traits>
4
1
  export module napi_js:string_table;
5
2
  import :reference;
6
3
  import auto_js;
4
+ import std;
7
5
  import util;
8
6
  using namespace std::string_literals;
9
7
 
@@ -26,8 +24,8 @@ struct string_table_options {
26
24
  export template <const auto& Strings, string_table_options Options = {}>
27
25
  class string_table {
28
26
  public:
29
- auto string_table_storage(const auto& string_value) {
30
- constexpr auto string_sv = util::consteval_string_view{string_value};
27
+ auto string_table_storage(auto string_value) {
28
+ constexpr auto string_sv = util::make_consteval_string_view(string_value);
31
29
  constexpr auto index = string_table_of<Strings>.lookup(string_sv);
32
30
  if constexpr (index) {
33
31
  return util::just<napi::reference<string_tag>&>{string_literal_storage_.at(index).second};
@@ -1,8 +1,8 @@
1
1
  module;
2
- #include <functional>
2
+ #include "auto_js/no_unique_address.h"
3
3
  export module napi_js:utility;
4
- import :environment;
5
4
  import nodejs;
5
+ import std;
6
6
  import util;
7
7
 
8
8
  namespace js::napi {
@@ -11,47 +11,71 @@ namespace js::napi {
11
11
 
12
12
  // Null handle for both direct and indirect handles
13
13
  // Note: 1 -> 0x1'0000'0000
14
- const void* null_value_handle_ = nullptr;
15
- export auto* const null_value_handle = reinterpret_cast<napi_value>(&null_value_handle_);
14
+ const std::uint64_t null_value_handle_data = 0x7f7f'7f7f'7f7f'7f7f;
15
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
16
+ auto* const null_value_handle = reinterpret_cast<napi_value>(const_cast<std::uint64_t*>(&null_value_handle_data));
16
17
 
17
- // Address equality for underlying napi handles.
18
+ // Unwrap the v8 address of the napi handle. This points into the v8 heap.
18
19
  // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
19
- export struct virtual_address_equal {
20
+ struct virtual_handle_address {
20
21
  protected:
21
- ~virtual_address_equal() = default;
22
+ ~virtual_handle_address() = default;
22
23
 
23
24
  public:
24
- virtual auto operator()(napi_value left, napi_value right) const -> bool = 0;
25
+ virtual auto operator()(napi_value value) const noexcept -> void* = 0;
25
26
  };
26
27
 
27
- export struct direct_address_equal final : virtual_address_equal {
28
- auto operator()(napi_value left, napi_value right) const -> bool final {
29
- return left == right;
28
+ struct direct_handle_address final : virtual_handle_address {
29
+ auto operator()(napi_value value) const noexcept -> void* final {
30
+ return value;
30
31
  }
31
32
  };
32
33
 
33
- export struct indirect_address_equal final : virtual_address_equal {
34
- auto operator()(napi_value left, napi_value right) const -> bool final {
35
- auto* indirect_left = reinterpret_cast<void**>(left);
36
- auto* indirect_right = reinterpret_cast<void**>(right);
37
- return *indirect_left == *indirect_right;
34
+ struct indirect_handle_address final : virtual_handle_address {
35
+ auto operator()(napi_value value) const noexcept -> void* final {
36
+ return *reinterpret_cast<void**>(value);
38
37
  }
39
38
  };
40
39
 
41
- // Equality comparator which respects napi's handle types
40
+ // Address equality for underlying napi handles.
41
+ // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
42
+ struct virtual_address_equal {
43
+ protected:
44
+ ~virtual_address_equal() = default;
45
+
46
+ public:
47
+ virtual auto operator()(napi_value left, napi_value right) const noexcept -> bool = 0;
48
+ };
49
+
50
+ template <class Address>
51
+ struct virtual_address_equal_of final : virtual_address_equal {
52
+ public:
53
+ auto operator()(napi_value left, napi_value right) const noexcept -> bool final {
54
+ return address_(left) == address_(right);
55
+ }
56
+
57
+ private:
58
+ NO_UNIQUE_ADDRESS Address address_;
59
+ };
60
+
61
+ using direct_address_equal = virtual_address_equal_of<direct_handle_address>;
62
+ using indirect_address_equal = virtual_address_equal_of<indirect_handle_address>;
63
+
64
+ // Polymorphic address equality operator
42
65
  export class address_equal {
43
66
  private:
44
67
  using virtual_equal_type = util::covariant_value<virtual_address_equal, direct_address_equal, indirect_address_equal>;
45
68
 
46
69
  public:
47
- explicit address_equal(const environment& env) :
70
+ explicit address_equal(bool uses_direct_handles) :
48
71
  equal_{
49
- env.uses_direct_handles()
72
+ uses_direct_handles
50
73
  ? virtual_equal_type{direct_address_equal{}}
51
74
  : virtual_equal_type{indirect_address_equal{}}
52
75
  } {}
53
76
 
54
- auto operator()(napi_value left, napi_value right) const -> bool {
77
+ auto operator()(napi_value left, napi_value right) const noexcept -> bool {
78
+ // NOLINTNEXTLINE(bugprone-exception-escape)
55
79
  return (*equal_)(left, right);
56
80
  }
57
81
 
@@ -60,17 +84,19 @@ export class address_equal {
60
84
  };
61
85
 
62
86
  // Address hash for napi value handles.
63
- export struct direct_address_hash : std::hash<void*> {};
64
-
65
- export struct indirect_address_hash : std::hash<void*> {
66
- private:
67
- using std::hash<void*>::operator();
68
-
87
+ template <class Address>
88
+ struct address_hash_of final {
69
89
  public:
70
90
  auto operator()(napi_value value) const noexcept -> std::size_t {
71
- auto* indirect_handle = reinterpret_cast<void**>(value);
72
- return (*this)(*indirect_handle);
91
+ return hash_(address_(value));
73
92
  }
93
+
94
+ private:
95
+ NO_UNIQUE_ADDRESS Address address_;
96
+ NO_UNIQUE_ADDRESS std::hash<void*> hash_;
74
97
  };
75
98
 
99
+ using direct_address_hash = address_hash_of<direct_handle_address>;
100
+ using indirect_address_hash = address_hash_of<indirect_handle_address>;
101
+
76
102
  } // namespace js::napi
@@ -1,349 +1,153 @@
1
- module;
2
- #include <concepts>
3
- #include <string_view>
4
- #include <tuple>
5
- #include <utility>
6
- #include <variant>
7
- #include <vector>
8
- export module napi_js:accept;
9
- import :api;
10
- import :container;
11
- import :environment_fwd;
12
- import :value;
13
- import util;
1
+ module napi_js;
2
+ import std;
14
3
 
15
- namespace js {
16
- using namespace napi;
4
+ namespace js::napi {
17
5
 
18
- // Generic napi acceptor which accepts all value types.
19
- template <class Environment>
20
- struct accept_napi_value;
21
-
22
- template <class Meta>
23
- using accept_napi_value_with = accept_napi_value<typename Meta::accept_context_type>;
24
-
25
- template <class Environment>
26
- struct accept_napi_value : napi::environment_scope<Environment> {
27
- public:
28
- // nb: This marks this acceptor as referential!
29
- using accept_reference_type = napi_value;
30
-
31
- using napi::environment_scope<Environment>::environment;
32
-
33
- explicit accept_napi_value(auto* /*transfer*/, auto& env) :
34
- napi::environment_scope<Environment>{env} {}
35
-
36
- // reference provider
37
- constexpr auto operator()(std::type_identity<napi_value> /*type*/, napi_value value) const -> napi_value { return value; }
38
-
39
- template <class Tag>
40
- constexpr auto operator()(std::type_identity<napi::value<Tag>> /*type*/, napi_value value) const -> napi::value<Tag> {
41
- return napi::value<Tag>::from(value);
42
- }
6
+ // undefined & null
7
+ auto accept_basic_napi_value::operator()(undefined_tag /*tag*/, visit_holder /*visit*/, std::monostate /*subject*/) const -> value_of<undefined_tag> {
8
+ return value_of<undefined_tag>::from(napi::invoke(napi_get_undefined, napi_env{*this}));
9
+ }
43
10
 
44
- // undefined & null
45
- auto operator()(undefined_tag /*tag*/, visit_holder /*visit*/, const auto& /*undefined*/) const -> napi::value<undefined_tag> {
46
- return napi::value<undefined_tag>::make(environment(), std::monostate{});
47
- }
11
+ auto accept_basic_napi_value::operator()(null_tag /*tag*/, visit_holder /*visit*/, std::nullptr_t /*subject*/) const -> value_of<null_tag> {
12
+ return value_of<null_tag>::from(napi::invoke(napi_get_null, napi_env{*this}));
13
+ }
48
14
 
49
- auto operator()(null_tag /*tag*/, visit_holder /*visit*/, const auto& /*null*/) const -> napi::value<null_tag> {
50
- return napi::value<null_tag>::make(environment(), nullptr);
51
- }
15
+ // boolean
16
+ auto accept_basic_napi_value::operator()(boolean_tag /*tag*/, visit_holder /*visit*/, bool subject) const -> value_of<boolean_tag> {
17
+ return value_of<boolean_tag>::from(napi::invoke(napi_get_boolean, napi_env{*this}, subject));
18
+ }
52
19
 
53
- // boolean
54
- auto operator()(boolean_tag /*tag*/, visit_holder /*visit*/, auto&& subject) const -> napi::value<boolean_tag> {
55
- return napi::value<boolean_tag>::make(environment(), bool{std::forward<decltype(subject)>(subject)});
56
- }
20
+ // number
21
+ auto accept_basic_napi_value::operator()(number_tag_of<double> /*tag*/, visit_holder /*visit*/, double subject) const -> value_of<number_tag_of<double>> {
22
+ return value_of<number_tag_of<double>>::from(napi::invoke(napi_create_double, napi_env{*this}, subject));
23
+ }
57
24
 
58
- // number
59
- auto operator()(number_tag /*tag*/, visit_holder visit, auto&& subject) const -> napi::value<number_tag> {
60
- return (*this)(number_tag_of<double>{}, visit, std::forward<decltype(subject)>(subject));
61
- }
25
+ auto accept_basic_napi_value::operator()(number_tag_of<std::int32_t> /*tag*/, visit_holder /*visit*/, std::int32_t subject) const -> value_of<number_tag_of<std::int32_t>> {
26
+ return value_of<number_tag_of<std::int32_t>>::from(napi::invoke(napi_create_int32, napi_env{*this}, subject));
27
+ }
62
28
 
63
- template <class Numeric>
64
- auto operator()(number_tag_of<Numeric> /*tag*/, visit_holder /*visit*/, auto&& subject) const -> napi::value<number_tag> {
65
- return napi::value<number_tag>::make(environment(), Numeric{std::forward<decltype(subject)>(subject)});
66
- }
29
+ auto accept_basic_napi_value::operator()(number_tag_of<std::uint32_t> /*tag*/, visit_holder /*visit*/, std::uint32_t subject) const -> value_of<number_tag_of<std::uint32_t>> {
30
+ return value_of<number_tag_of<std::uint32_t>>::from(napi::invoke(napi_create_uint32, napi_env{*this}, subject));
31
+ }
67
32
 
68
- // bigint
69
- auto operator()(bigint_tag /*tag*/, visit_holder visit, auto&& subject) const
70
- -> js::referenceable_value<napi::value<bigint_tag>> {
71
- return (*this)(bigint_tag_of<bigint>{}, visit, std::forward<decltype(subject)>(subject));
72
- }
33
+ // string
34
+ auto accept_basic_napi_value::operator()(string_tag_of<char> /*tag*/, visit_holder /*visit*/, std::string_view subject) const
35
+ -> js::referenceable_value<value_of<string_tag_of<char>>> {
36
+ auto* value = napi::invoke(napi_create_string_latin1, napi_env{*this}, subject.data(), subject.length());
37
+ return js::referenceable_value{value_of<string_tag_of<char>>::from(value)};
38
+ }
73
39
 
74
- auto operator()(bigint_tag_of<bigint> /*tag*/, visit_holder /*visit*/, auto&& subject) const
75
- -> js::referenceable_value<napi::value<bigint_tag>> {
76
- return js::referenceable_value{napi::value<bigint_tag>::make(environment(), js::bigint{std::forward<decltype(subject)>(subject)})};
77
- }
40
+ auto accept_basic_napi_value::operator()(string_tag_of<char8_t> /*tag*/, visit_holder /*visit*/, std::u8string_view subject) const
41
+ -> js::referenceable_value<value_of<string_tag_of<char8_t>>> {
42
+ auto* value = napi::invoke(napi_create_string_utf8, napi_env{*this}, reinterpret_cast<const char*>(subject.data()), subject.length());
43
+ return js::referenceable_value{value_of<string_tag_of<char8_t>>::from(value)};
44
+ }
78
45
 
79
- auto operator()(bigint_tag_of<bigint> /*tag*/, visit_holder /*visit*/, const js::bigint& subject) const
80
- -> js::referenceable_value<napi::value<bigint_tag>> {
81
- return js::referenceable_value{napi::value<bigint_tag>::make(environment(), subject)};
82
- }
46
+ auto accept_basic_napi_value::operator()(string_tag_of<char16_t> /*tag*/, visit_holder /*visit*/, std::u16string_view subject) const
47
+ -> js::referenceable_value<value_of<string_tag_of<char16_t>>> {
48
+ auto* value = napi::invoke(napi_create_string_utf16, napi_env{*this}, subject.data(), subject.length());
49
+ return js::referenceable_value{value_of<string_tag_of<char16_t>>::from(value)};
50
+ }
83
51
 
84
- template <class Numeric>
85
- auto operator()(bigint_tag_of<Numeric> /*tag*/, visit_holder /*visit*/, auto&& subject) const
86
- -> js::referenceable_value<napi::value<bigint_tag>> {
87
- return js::referenceable_value{napi::value<bigint_tag>::make(environment(), Numeric{std::forward<decltype(subject)>(subject)})};
88
- }
52
+ // bigint
53
+ auto accept_basic_napi_value::operator()(bigint_tag_of<std::int64_t> /*tag*/, visit_holder /*visit*/, std::int64_t subject) const
54
+ -> js::referenceable_value<value_of<bigint_tag_of<std::int64_t>>> {
55
+ auto* value = napi::invoke(napi_create_bigint_int64, napi_env{*this}, subject);
56
+ return js::referenceable_value{value_of<bigint_tag_of<std::int64_t>>::from(value)};
57
+ }
89
58
 
90
- // string
91
- auto operator()(string_tag /*tag*/, visit_holder visit, auto&& subject) const
92
- -> js::referenceable_value<napi::value<string_tag>> {
93
- return (*this)(string_tag_of<char16_t>{}, visit, std::forward<decltype(subject)>(subject));
94
- }
59
+ auto accept_basic_napi_value::operator()(bigint_tag_of<std::uint64_t> /*tag*/, visit_holder /*visit*/, std::uint64_t subject) const
60
+ -> js::referenceable_value<value_of<bigint_tag_of<std::uint64_t>>> {
61
+ auto* value = napi::invoke(napi_create_bigint_uint64, napi_env{*this}, subject);
62
+ return js::referenceable_value{value_of<bigint_tag_of<std::uint64_t>>::from(value)};
63
+ }
95
64
 
96
- template <class Char>
97
- auto operator()(string_tag_of<Char> /*tag*/, visit_holder /*visit*/, std::convertible_to<std::basic_string_view<Char>> auto&& subject) const
98
- -> js::referenceable_value<napi::value<string_tag>> {
99
- return js::referenceable_value{napi::value<string_tag>::make(environment(), std::basic_string_view<Char>{std::forward<decltype(subject)>(subject)})};
100
- }
65
+ auto accept_basic_napi_value::operator()(bigint_tag_of<js::bigint> /*tag*/, visit_holder /*visit*/, const js::bigint& subject) const
66
+ -> js::referenceable_value<value_of<bigint_tag_of<js::bigint>>> {
67
+ auto* value = napi::invoke(napi_create_bigint_words, napi_env{*this}, subject.sign_bit(), subject.size(), subject.data());
68
+ return js::referenceable_value{value_of<bigint_tag_of<js::bigint>>::from(value)};
69
+ }
101
70
 
102
- template <class Char>
103
- auto operator()(string_tag_of<Char> tag, visit_holder visit, auto&& subject) const
104
- -> js::referenceable_value<napi::value<string_tag>> {
105
- return (*this)(tag, visit, std::basic_string<Char>{std::forward<decltype(subject)>(subject)});
106
- }
71
+ // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
72
+ auto accept_basic_napi_value::operator()(bigint_tag_of<js::bigint> tag, visit_holder visit, js::bigint&& subject) const
73
+ -> js::referenceable_value<value_of<bigint_tag_of<js::bigint>>> {
74
+ return (*this)(tag, visit, static_cast<const js::bigint&>(subject));
75
+ }
107
76
 
108
- // date
109
- auto operator()(date_tag /*tag*/, visit_holder /*visit*/, auto&& subject) const
110
- -> js::referenceable_value<napi::value<date_tag>> {
111
- return js::referenceable_value{napi::value<date_tag>::make(environment(), js_clock::time_point{std::forward<decltype(subject)>(subject)})};
112
- }
77
+ // date
78
+ auto accept_basic_napi_value::operator()(date_tag /*tag*/, visit_holder /*visit*/, js_clock::time_point subject) const
79
+ -> js::referenceable_value<value_of<date_tag>> {
80
+ auto value = value_of<date_tag>::from(napi::invoke(napi_create_date, napi_env{*this}, subject.time_since_epoch().count()));
81
+ return js::referenceable_value{value};
82
+ }
113
83
 
114
- // function
115
- template <class Callback>
116
- auto operator()(function_tag /*tag*/, visit_holder /*visit*/, js::free_function<Callback> subject) const -> napi::value<function_tag> {
117
- return napi::value<function_tag>::make(environment(), std::forward<decltype(subject)>(subject));
118
- }
84
+ // error
85
+ auto accept_basic_napi_value::operator()(error_tag /*tag*/, visit_holder visit, const js::error_value& subject) const
86
+ -> js::referenceable_value<value_of<error_tag>> {
87
+ auto* message = napi_value{js::transfer_in<value_of<string_tag>>(subject.message(), environment())};
88
+ auto* error = [ & ] -> napi_value {
89
+ switch (subject.name()) {
90
+ default:
91
+ return napi::invoke(napi_create_error, napi_env{*this}, napi_value{}, message);
92
+ case js::error_name::range_error:
93
+ return napi::invoke(napi_create_range_error, napi_env{*this}, napi_value{}, message);
94
+ case js::error_name::syntax_error:
95
+ return napi::invoke(node_api_create_syntax_error, napi_env{*this}, napi_value{}, message);
96
+ case js::error_name::type_error:
97
+ return napi::invoke(napi_create_type_error, napi_env{*this}, napi_value{}, message);
98
+ }
99
+ }();
100
+ auto stack = (*this)(string_tag{}, visit, subject.stack());
101
+ napi::invoke0(napi_set_named_property, napi_env{*this}, error, "stack", *std::move(stack));
102
+ return js::referenceable_value{value_of<error_tag>::from(error)};
103
+ }
119
104
 
120
- // error
121
- auto operator()(error_tag /*tag*/, visit_holder /*visit*/, const auto& subject) const
122
- -> js::referenceable_value<napi::value<error_tag>> {
123
- auto* message = napi_value{napi::value<string_tag>::make(environment(), subject.message())};
124
- auto error = [ & ]() -> napi_value {
125
- switch (subject.name()) {
126
- default:
127
- return napi::invoke(napi_create_error, napi_env{*this}, napi_value{}, message);
128
- case js::error::name_type::range_error:
129
- return napi::invoke(napi_create_range_error, napi_env{*this}, napi_value{}, message);
130
- case js::error::name_type::syntax_error:
131
- return napi::invoke(node_api_create_syntax_error, napi_env{*this}, napi_value{}, message);
132
- case js::error::name_type::type_error:
133
- return napi::invoke(napi_create_type_error, napi_env{*this}, napi_value{}, message);
134
- }
135
- }();
136
- return js::referenceable_value{napi::value<error_tag>::from(error)};
137
- }
105
+ // data blocks (array buffer, shared array buffer)
106
+ auto accept_basic_napi_value::operator()(array_buffer_tag /*tag*/, visit_holder /*visit*/, const js::array_buffer& subject) const
107
+ -> js::referenceable_value<value_of<array_buffer_tag>> {
108
+ // You could avoid the extra copy for `js::data_block&&` here w/ v8 API. Napi requires the copy
109
+ // though.
110
+ // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
111
+ void* bytes;
112
+ auto* result = napi::invoke(napi_create_arraybuffer, napi_env{*this}, subject.size(), &bytes);
113
+ // nb: `std::memcpy` *technically* results in undefined behavior on block size 0
114
+ // (and also) it maybe causes an infinite loop with musl
115
+ // https://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0
116
+ std::ranges::copy(std::span<const std::byte>{subject}, static_cast<std::byte*>(bytes));
117
+ auto value = value_of<array_buffer_tag>::from(result);
118
+ return js::referenceable_value{value};
119
+ }
138
120
 
139
- // vectors
140
- auto operator()(this const auto& self, vector_tag /*tag*/, auto& visit, auto&& subject)
141
- -> js::deferred_receiver<napi::value<vector_tag>, decltype(self), decltype(visit), decltype(subject)> {
142
- return {
143
- napi::value<vector_tag>::from(napi::invoke(napi_create_array_with_length, napi_env{self}, subject.size())),
144
- std::forward_as_tuple(self, visit, std::forward<decltype(subject)>(subject)),
145
- [](napi::value<vector_tag> array, auto& self, auto& visit, auto /*&&*/ subject) -> void {
146
- int ii = 0;
147
- auto&& range = util::into_range(std::forward<decltype(subject)>(subject));
148
- for (auto&& subject : util::forward_range(std::forward<decltype(range)>(range))) {
149
- auto* element = napi_value{visit(std::forward<decltype(subject)>(subject), self)};
150
- napi::invoke0(napi_set_element, napi_env{self}, napi_value{array}, ii++, element);
151
- }
121
+ auto accept_basic_napi_value::operator()(shared_array_buffer_tag /*tag*/, visit_holder /*visit*/, js::shared_array_buffer&& subject) const
122
+ -> js::referenceable_value<value_of<shared_array_buffer_tag>> {
123
+ auto backing_store = [ & ]() -> auto {
124
+ auto byte_length = subject.size();
125
+ // v8 does not call the deleter `byte_length` is zero. So the heap-allocated shared_ptr trick
126
+ // does not work in that case.
127
+ if (byte_length == 0) {
128
+ return v8::SharedArrayBuffer::NewBackingStore(nullptr, 0, nullptr, nullptr);
129
+ } else {
130
+ auto holder = std::make_unique<js::shared_array_buffer::shared_pointer_type>(std::move(subject).acquire_ownership());
131
+ auto backing_store = v8::SharedArrayBuffer::NewBackingStore(
132
+ holder->get(),
133
+ byte_length,
134
+ [](void* /*data*/, std::size_t /*length*/, void* param) -> void {
135
+ delete static_cast<js::shared_array_buffer::shared_pointer_type*>(param);
152
136
  },
153
- };
154
- }
155
-
156
- template <std::size_t Size>
157
- auto operator()(this const auto& self, tuple_tag<Size> /*tag*/, auto& visit, auto&& subject)
158
- -> js::deferred_receiver<napi::value<vector_tag>, decltype(self), decltype(visit), decltype(subject)> {
159
- return {
160
- napi::value<vector_tag>::from(napi::invoke(napi_create_array_with_length, napi_env{self}, Size)),
161
- std::forward_as_tuple(self, visit, std::forward<decltype(subject)>(subject)),
162
- [](napi::value<vector_tag> array, auto& self, auto& visit, auto /*&&*/ tuple) -> void {
163
- const auto [... indices ] = util::sequence<Size>;
164
- (..., [ & ]() -> void {
165
- // nb: This is forwarded to *each* visitor. The visitor should be aware and only lvalue
166
- // reference members one at a time.
167
- auto* element = napi_value{visit(indices, std::forward<decltype(tuple)>(tuple), self)};
168
- napi::invoke0(napi_set_element, napi_env{self}, napi_value{array}, indices, element);
169
- }());
170
- }
171
- };
172
- }
173
-
174
- // arrays & dictionaries
175
- auto operator()(this const auto& self, list_tag /*tag*/, auto& visit, auto&& subject)
176
- -> js::deferred_receiver<napi::value<list_tag>, decltype(self), decltype(visit), decltype(subject)> {
177
- return {
178
- napi::value<list_tag>::from(napi::invoke(napi_create_array, napi_env{self})),
179
- std::forward_as_tuple(self, visit, std::forward<decltype(subject)>(subject)),
180
- [](napi::value<list_tag> array, auto& self, auto& visit, auto /*&&*/ subject) -> void {
181
- self.accept_entry_pair_vector(visit, array, std::forward<decltype(subject)>(subject));
182
- }
183
- };
184
- }
185
-
186
- auto operator()(this const auto& self, dictionary_tag /*tag*/, auto& visit, auto&& subject)
187
- -> js::deferred_receiver<napi::value<dictionary_tag>, decltype(self), decltype(visit), decltype(subject)> {
188
- return {
189
- napi::value<dictionary_tag>::from(napi::invoke(napi_create_object, napi_env{self})),
190
- std::forward_as_tuple(self, visit, std::forward<decltype(subject)>(subject)),
191
- [](napi::value<dictionary_tag> object, auto& self, auto& visit, auto /*&&*/ subject) -> void {
192
- self.accept_entry_pair_vector(visit, object, std::forward<decltype(subject)>(subject));
193
- }
194
- };
195
- }
196
-
197
- auto accept_entry_pair_vector(this const auto& self, auto& visit, value<object_tag> target, auto&& subject) -> void {
198
- std::vector<napi_property_descriptor> properties;
199
- auto&& range = util::into_range(std::forward<decltype(subject)>(subject));
200
- properties.reserve(std::size(range));
201
- for (auto&& [ key, value ] : util::forward_range(std::forward<decltype(range)>(range))) {
202
- properties.emplace_back(napi_property_descriptor{
203
- .utf8name{},
204
- .name = napi_value{visit.first(std::forward<decltype(key)>(key), self)},
205
-
206
- .method{},
207
- .getter{},
208
- .setter{},
209
- .value = napi_value{visit.second(std::forward<decltype(value)>(value), self)},
210
-
211
- // NOLINTNEXTLINE(hicpp-signed-bitwise)
212
- .attributes = static_cast<napi_property_attributes>(napi_writable | napi_enumerable | napi_configurable),
213
- .data{},
214
- });
215
- }
216
- napi::invoke0(napi_define_properties, napi_env{self}, napi_value{target}, properties.size(), properties.data());
217
- }
218
-
219
- // structs
220
- template <std::size_t Size>
221
- auto operator()(this const auto& self, struct_tag<Size> /*tag*/, auto& visit, auto&& subject)
222
- -> js::deferred_receiver<napi::value<dictionary_tag>, decltype(self), decltype(visit), decltype(subject)> {
223
- return {
224
- napi::value<dictionary_tag>::from(napi::invoke(napi_create_object, napi_env{self})),
225
- std::forward_as_tuple(self, visit, std::forward<decltype(subject)>(subject)),
226
- [](napi::value<dictionary_tag> object, auto& self, auto& visit, auto /*&&*/ subject) -> void {
227
- self.template accept_entry_pair_struct<Size>(visit, object, std::forward<decltype(subject)>(subject));
228
- }
229
- };
230
- }
231
-
232
- template <std::size_t Size>
233
- auto accept_entry_pair_struct(this const auto& self, auto& visit, value<object_tag> target, auto&& subject) -> void {
234
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
235
- std::array<napi_property_descriptor, Size> properties;
236
- const auto [... indices ] = util::sequence<Size>;
237
- (..., [ & ]() -> void {
238
- // nb: This is forwarded to *each* visitor. The visitor should be aware and only lvalue
239
- // reference members one at a time.
240
- auto accept_entry = accept_entry_pair<decltype(self), decltype(self)>{self};
241
- auto entry = visit(std::integral_constant<std::size_t, indices>{}, std::forward<decltype(subject)>(subject), accept_entry);
242
- // NOLINTNEXTLINE(modernize-type-traits)
243
- properties.at(indices) = {
244
- .utf8name{},
245
- .name = entry.first,
246
-
247
- .method{},
248
- .getter{},
249
- .setter{},
250
- .value = entry.second,
251
-
252
- // NOLINTNEXTLINE(hicpp-signed-bitwise)
253
- .attributes = static_cast<napi_property_attributes>(napi_writable | napi_enumerable | napi_configurable),
254
- .data{},
255
- };
256
- }());
257
- napi::invoke0(napi_define_properties, napi_env{self}, napi_value{target}, properties.size(), properties.data());
258
- }
259
-
260
- // no required types
261
- consteval static auto types(auto /*recursive*/) { return util::type_pack{}; }
262
- };
263
-
264
- // Plain napi_value acceptor
265
- template <>
266
- struct accept_property_subject<napi_value> : std::type_identity<napi_value> {};
267
-
268
- template <class Meta>
269
- struct accept<Meta, napi_value> : accept_napi_value_with<Meta> {
270
- using accept_type = accept_napi_value_with<Meta>;
271
- using accept_type::accept_type;
272
- };
273
-
274
- // Tagged `napi::value<T>` acceptor
275
- template <>
276
- struct accept_property_subject<napi::value<value_tag>> : std::type_identity<napi_value> {};
277
-
278
- template <class Meta>
279
- struct accept<Meta, napi::value<value_tag>> : accept_napi_value_with<Meta> {
280
- using accept_type = accept_napi_value_with<Meta>;
281
- using accept_type::accept_type;
282
- };
283
-
284
- // Forwarded `napi::value<T>` acceptor
285
- template <class Tag>
286
- struct accept<void, js::forward<napi::value<Tag>, Tag>> {
287
- auto operator()(Tag /*tag*/, visit_holder /*visit*/, napi::value<Tag> value) const -> js::forward<napi::value<Tag>, Tag> {
288
- return js::forward{napi::value<Tag>{value}, Tag{}};
289
- }
290
-
291
- consteval static auto types(auto /*recursive*/) { return util::type_pack{}; }
292
- };
293
-
294
- // Object key lookup via napi
295
- template <class Meta, auto Key, class Type>
296
- struct accept_property_value<Meta, Key, Type, napi_value> {
297
- public:
298
- explicit constexpr accept_property_value(auto* transfer) :
299
- first{transfer},
300
- second{transfer} {}
301
-
302
- auto operator()(dictionary_tag /*tag*/, auto& visit, const auto& object) const -> Type {
303
- if (auto local = first(std::type_identity<void>{}, visit.first); object.has(local)) {
304
- return visit.second(object.get(local), second);
305
- } else {
306
- return second(undefined_in_tag{}, visit.second, std::monostate{});
307
- }
308
- }
309
-
310
- private:
311
- mutable visit_key_literal<Key, napi_value> first;
312
- accept_value<Meta, Type> second;
313
- };
314
-
315
- // `value<object_tag>{}.assign(...)` implementation
316
- struct object_assign_delegate {
317
- public:
318
- explicit object_assign_delegate(value<object_tag> object) : object_{object} {}
319
- auto operator*() const { return object_; }
320
-
321
- private:
322
- value<object_tag> object_;
323
- };
324
-
325
- template <class Meta>
326
- struct accept<Meta, object_assign_delegate> {
327
- public:
328
- accept(auto* transfer, auto& env, object_assign_delegate object) :
329
- accept_{transfer, env},
330
- object_{object} {}
331
-
332
- template <std::size_t Size>
333
- auto operator()(this const auto& self, tuple_tag<Size> /*tag*/, auto& visit, auto&& subject) -> object_assign_delegate {
334
- self.accept_.template accept_entry_pair_struct<Size>(visit, *self.object_, std::forward<decltype(subject)>(subject));
335
- return self.object_;
336
- }
337
-
338
- consteval static auto types(auto recursive) { return accept<Meta, napi_value>::types(recursive); }
339
-
340
- private:
341
- accept_value<Meta, napi_value> accept_;
342
- object_assign_delegate object_;
343
- };
137
+ holder.get()
138
+ );
139
+ std::ignore = holder.release();
140
+ return backing_store;
141
+ }
142
+ }();
143
+ auto shared_array_buffer = v8::SharedArrayBuffer::New(v8::Isolate::GetCurrent(), std::move(backing_store));
144
+ auto value = value_of<shared_array_buffer_tag>::from(std::bit_cast<napi_value>(shared_array_buffer));
145
+ return js::referenceable_value{value};
146
+ }
344
147
 
345
- auto value_for_object::assign(this value<object_tag> self, auto_environment auto& env, auto source) -> void {
346
- js::transfer_in<object_assign_delegate>(std::move(source), env, object_assign_delegate{self});
148
+ auto accept_basic_napi_value::operator()(shared_array_buffer_tag tag, visit_holder visit, const js::shared_array_buffer& subject) const
149
+ -> js::referenceable_value<value_of<shared_array_buffer_tag>> {
150
+ return (*this)(tag, visit, js::shared_array_buffer{subject});
347
151
  }
348
152
 
349
- } // namespace js
153
+ } // namespace js::napi