@auto_js/napi 0.0.5 → 0.0.7

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.
@@ -0,0 +1,230 @@
1
+ module napi_js;
2
+ import std;
3
+ import v8;
4
+
5
+ namespace js::napi {
6
+ util::lockable_with<bool, {.shared = true}> host_environment_initialized;
7
+
8
+ // Addressof operations
9
+ constexpr auto direct_handle_address =
10
+ [](napi_value value) noexcept -> void* { return value; };
11
+
12
+ constexpr auto indirect_handle_address =
13
+ [](napi_value value) noexcept -> void* { return *reinterpret_cast<void**>(value); };
14
+
15
+ // Value inspection
16
+ constexpr auto v8_maybe_fast_is_number_int32 =
17
+ [](value_of<number_tag> value) -> std::optional<bool> { return std::bit_cast<v8::Local<v8::Number>>(value)->IsInt32(); };
18
+
19
+ constexpr auto v8_maybe_fast_is_string_one_byte =
20
+ [](value_of<string_tag> value) -> std::optional<bool> { return std::bit_cast<v8::Local<v8::String>>(value)->IsOneByte(); };
21
+
22
+ constexpr auto napi_maybe_is_shared_array_buffer =
23
+ [](napi_env env, value_of<object_tag> value) -> std::optional<bool> { return napi::invoke(node_api_is_sharedarraybuffer, env, value); };
24
+
25
+ constexpr auto unknown_maybe_fast_is_number_int32 =
26
+ [](value_of<number_tag> /*value*/) -> std::optional<bool> { return std::nullopt; };
27
+
28
+ constexpr auto unknown_maybe_fast_is_string_one_byte =
29
+ [](value_of<string_tag> /*value*/) -> std::optional<bool> { return std::nullopt; };
30
+
31
+ constexpr auto unknown_maybe_is_shared_array_buffer =
32
+ [](napi_env /*env*/, value_of<object_tag> /*value*/) -> std::optional<bool> { return std::nullopt; };
33
+
34
+ auto fast_is_array(napi_value value) -> bool {
35
+ return std::bit_cast<v8::Local<v8::Value>>(value)->IsArray();
36
+ }
37
+
38
+ auto fast_is_bigint(napi_value value) -> bool {
39
+ return std::bit_cast<v8::Local<v8::Value>>(value)->IsBigInt();
40
+ }
41
+
42
+ auto fast_is_boolean(napi_value value) -> bool {
43
+ return std::bit_cast<v8::Local<v8::Value>>(value)->IsBoolean();
44
+ }
45
+
46
+ auto fast_is_function(napi_value value) -> bool {
47
+ return std::bit_cast<v8::Local<v8::Value>>(value)->IsFunction();
48
+ }
49
+
50
+ auto fast_is_null(napi_value value) -> bool {
51
+ return std::bit_cast<v8::Local<v8::Value>>(value)->IsNull();
52
+ }
53
+
54
+ auto fast_is_number(napi_value value) -> bool {
55
+ return std::bit_cast<v8::Local<v8::Value>>(value)->IsNumber();
56
+ }
57
+
58
+ auto fast_is_object(napi_value value) -> bool {
59
+ return std::bit_cast<v8::Local<v8::Value>>(value)->IsObject();
60
+ }
61
+
62
+ auto fast_is_string(napi_value value) -> bool {
63
+ return std::bit_cast<v8::Local<v8::Value>>(value)->IsString();
64
+ }
65
+
66
+ auto fast_is_undefined(napi_value value) -> bool {
67
+ return std::bit_cast<v8::Local<v8::Value>>(value)->IsUndefined();
68
+ }
69
+
70
+ // 'SharedArrayBuffer' constructors
71
+ constexpr auto v8_make_shared_array_buffer =
72
+ [](js::shared_array_buffer::shared_pointer_type data, std::size_t byte_length) -> value_of<shared_array_buffer_tag> {
73
+ auto backing_store = [ & ]() -> auto {
74
+ // v8 does not call the deleter `byte_length` is zero. So the heap-allocated shared_ptr trick
75
+ // does not work in that case.
76
+ if (byte_length == 0) {
77
+ return v8::SharedArrayBuffer::NewBackingStore(nullptr, 0, nullptr, nullptr);
78
+ } else {
79
+ auto holder = std::make_unique<js::shared_array_buffer::shared_pointer_type>(std::move(data));
80
+ auto backing_store = v8::SharedArrayBuffer::NewBackingStore(
81
+ holder->get(),
82
+ byte_length,
83
+ [](void* /*data*/, std::size_t /*length*/, void* param) -> void {
84
+ delete static_cast<js::shared_array_buffer::shared_pointer_type*>(param);
85
+ },
86
+ holder.get()
87
+ );
88
+ std::ignore = holder.release();
89
+ return backing_store;
90
+ }
91
+ }();
92
+ auto shared_array_buffer = v8::SharedArrayBuffer::New(v8::Isolate::GetCurrent(), std::move(backing_store));
93
+ return value_of<shared_array_buffer_tag>::from(std::bit_cast<napi_value>(shared_array_buffer));
94
+ };
95
+
96
+ constexpr auto unknown_make_shared_array_buffer =
97
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
98
+ [](js::shared_array_buffer::shared_pointer_type /*data*/, std::size_t /*byte_length*/) -> value_of<shared_array_buffer_tag> {
99
+ throw js::type_error{u"SharedArrayBuffer is not supported in this environment"};
100
+ };
101
+
102
+ // 'ArrayBufferView' constructors
103
+ constexpr auto v8_make_sab_data_view =
104
+ // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
105
+ [](value_of<shared_array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> value_of<data_view_tag> {
106
+ auto buffer_local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{buffer});
107
+ auto view_local = v8::DataView::New(buffer_local, byte_offset, length);
108
+ return value_of<data_view_tag>::from(std::bit_cast<napi_value>(view_local));
109
+ };
110
+
111
+ constexpr auto unknown_make_sab_data_view =
112
+ // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
113
+ [](value_of<shared_array_buffer_tag> /*buffer*/, std::size_t /*byte_offset*/, std::size_t /*length*/) -> value_of<data_view_tag> {
114
+ throw js::type_error{u"SharedArrayBuffer is not supported in this environment"};
115
+ };
116
+
117
+ template <class Type>
118
+ constexpr auto v8_make_sab_typed_array_of =
119
+ // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
120
+ [](value_of<shared_array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> value_of<typed_array_tag_of<Type>> {
121
+ using constructor_type = type_t<util::overloaded{
122
+ [](std::type_identity<double>) -> std::type_identity<v8::Float64Array> { return {}; },
123
+ [](std::type_identity<float>) -> std::type_identity<v8::Float32Array> { return {}; },
124
+ [](std::type_identity<js::float16_t>) -> std::type_identity<v8::Float16Array> { return {}; },
125
+ [](std::type_identity<js::uint8_clamped_t>) -> std::type_identity<v8::Uint8ClampedArray> { return {}; },
126
+ [](std::type_identity<std::int16_t>) -> std::type_identity<v8::Int16Array> { return {}; },
127
+ [](std::type_identity<std::int32_t>) -> std::type_identity<v8::Int32Array> { return {}; },
128
+ [](std::type_identity<std::int64_t>) -> std::type_identity<v8::BigInt64Array> { return {}; },
129
+ [](std::type_identity<std::int8_t>) -> std::type_identity<v8::Int8Array> { return {}; },
130
+ [](std::type_identity<std::uint16_t>) -> std::type_identity<v8::Uint16Array> { return {}; },
131
+ [](std::type_identity<std::uint32_t>) -> std::type_identity<v8::Uint32Array> { return {}; },
132
+ [](std::type_identity<std::uint64_t>) -> std::type_identity<v8::BigUint64Array> { return {}; },
133
+ [](std::type_identity<std::uint8_t>) -> std::type_identity<v8::Uint8Array> { return {}; },
134
+ }(type<Type>)>;
135
+ auto buffer_local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{buffer});
136
+ auto view_local = constructor_type::New(buffer_local, byte_offset, length);
137
+ return value_of<typed_array_tag_of<Type>>::from(std::bit_cast<napi_value>(view_local));
138
+ };
139
+
140
+ template <class Type>
141
+ constexpr auto unknown_make_sab_typed_array_of =
142
+ // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
143
+ [](value_of<shared_array_buffer_tag> /*buffer*/, std::size_t /*byte_offset*/, std::size_t /*length*/) -> value_of<typed_array_tag_of<Type>> {
144
+ throw js::type_error{u"SharedArrayBuffer is not supported in this environment"};
145
+ };
146
+
147
+ auto initialize_host_environment(napi_env env) -> void {
148
+ if (!*host_environment_initialized.read()) {
149
+ if (auto lock = host_environment_initialized.write(); !*lock) {
150
+ // Detect indirect handles (nodejs, v8 [configurable]) or direct handles (bun, jsc)
151
+ // See: `v8_enable_direct_handle`
152
+ auto uses_direct_handles = [ & ] -> bool {
153
+ auto* array = napi::invoke(napi_create_array_with_length, env, 1);
154
+ napi::invoke0(napi_set_element, env, array, 0, array);
155
+ auto* result = napi::invoke(napi_get_element, env, array, 0);
156
+ if (direct_handle_address(array) == direct_handle_address(result)) {
157
+ return true;
158
+ } else if (indirect_handle_address(array) == indirect_handle_address(result)) {
159
+ return false;
160
+ } else {
161
+ throw std::runtime_error{"Exotic napi handle behavior detected"};
162
+ }
163
+ }();
164
+ *lock = true;
165
+ if (uses_direct_handles) {
166
+ handle_addressof = direct_handle_address;
167
+ } else {
168
+ handle_addressof = indirect_handle_address;
169
+ }
170
+
171
+ // Detect bun via `process.isBun`
172
+ auto is_bun = [ & ] -> bool {
173
+ auto* global = napi::invoke(napi_get_global, env);
174
+ constexpr auto process_cw = util::make_consteval_string_view(util::cw<"process">);
175
+ auto* process_str = napi::invoke(node_api_create_property_key_latin1, env, process_cw.data(), process_cw.length());
176
+ auto* process = napi::invoke(napi_get_property, env, global, process_str);
177
+ if (napi::invoke(napi_typeof, env, process) == napi_object) {
178
+ constexpr auto is_bun_cw = util::make_consteval_string_view(util::cw<"isBun">);
179
+ auto* is_bun_str = napi::invoke(node_api_create_property_key_latin1, env, is_bun_cw.data(), is_bun_cw.length());
180
+ auto* is_bun = napi::invoke(napi_get_property, env, process, is_bun_str);
181
+ auto* is_bun_bool = napi::invoke(napi_coerce_to_bool, env, is_bun);
182
+ return napi::invoke(napi_get_value_bool, env, is_bun_bool);
183
+ } else {
184
+ return false;
185
+ }
186
+ }();
187
+ if (is_bun) {
188
+ has_fast_is_functions = false;
189
+ make_sab_data_view = unknown_make_sab_data_view;
190
+ make_sab_typed_array_of<double> = unknown_make_sab_typed_array_of<double>;
191
+ make_sab_typed_array_of<float> = unknown_make_sab_typed_array_of<float>;
192
+ make_sab_typed_array_of<js::float16_t> = unknown_make_sab_typed_array_of<js::float16_t>;
193
+ make_sab_typed_array_of<js::uint8_clamped_t> = unknown_make_sab_typed_array_of<js::uint8_clamped_t>;
194
+ make_sab_typed_array_of<std::int16_t> = unknown_make_sab_typed_array_of<std::int16_t>;
195
+ make_sab_typed_array_of<std::int32_t> = unknown_make_sab_typed_array_of<std::int32_t>;
196
+ make_sab_typed_array_of<std::int64_t> = unknown_make_sab_typed_array_of<std::int64_t>;
197
+ make_sab_typed_array_of<std::int8_t> = unknown_make_sab_typed_array_of<std::int8_t>;
198
+ make_sab_typed_array_of<std::uint16_t> = unknown_make_sab_typed_array_of<std::uint16_t>;
199
+ make_sab_typed_array_of<std::uint32_t> = unknown_make_sab_typed_array_of<std::uint32_t>;
200
+ make_sab_typed_array_of<std::uint64_t> = unknown_make_sab_typed_array_of<std::uint64_t>;
201
+ make_sab_typed_array_of<std::uint8_t> = unknown_make_sab_typed_array_of<std::uint8_t>;
202
+ make_shared_array_buffer = unknown_make_shared_array_buffer;
203
+ maybe_fast_is_number_int32 = unknown_maybe_fast_is_number_int32;
204
+ maybe_fast_is_string_one_byte = unknown_maybe_fast_is_string_one_byte;
205
+ maybe_is_shared_array_buffer = unknown_maybe_is_shared_array_buffer;
206
+ } else {
207
+ has_fast_is_functions = true;
208
+ make_sab_data_view = v8_make_sab_data_view;
209
+ make_sab_typed_array_of<double> = v8_make_sab_typed_array_of<double>;
210
+ make_sab_typed_array_of<float> = v8_make_sab_typed_array_of<float>;
211
+ make_sab_typed_array_of<js::float16_t> = v8_make_sab_typed_array_of<js::float16_t>;
212
+ make_sab_typed_array_of<js::uint8_clamped_t> = v8_make_sab_typed_array_of<js::uint8_clamped_t>;
213
+ make_sab_typed_array_of<std::int16_t> = v8_make_sab_typed_array_of<std::int16_t>;
214
+ make_sab_typed_array_of<std::int32_t> = v8_make_sab_typed_array_of<std::int32_t>;
215
+ make_sab_typed_array_of<std::int64_t> = v8_make_sab_typed_array_of<std::int64_t>;
216
+ make_sab_typed_array_of<std::int8_t> = v8_make_sab_typed_array_of<std::int8_t>;
217
+ make_sab_typed_array_of<std::uint16_t> = v8_make_sab_typed_array_of<std::uint16_t>;
218
+ make_sab_typed_array_of<std::uint32_t> = v8_make_sab_typed_array_of<std::uint32_t>;
219
+ make_sab_typed_array_of<std::uint64_t> = v8_make_sab_typed_array_of<std::uint64_t>;
220
+ make_sab_typed_array_of<std::uint8_t> = v8_make_sab_typed_array_of<std::uint8_t>;
221
+ make_shared_array_buffer = v8_make_shared_array_buffer;
222
+ maybe_fast_is_number_int32 = v8_maybe_fast_is_number_int32;
223
+ maybe_fast_is_string_one_byte = v8_maybe_fast_is_string_one_byte;
224
+ maybe_is_shared_array_buffer = napi_maybe_is_shared_array_buffer;
225
+ }
226
+ }
227
+ }
228
+ }
229
+
230
+ } // namespace js::napi
@@ -0,0 +1,56 @@
1
+ export module napi_js:support.host;
2
+ import :value_handle;
3
+ import std;
4
+
5
+ namespace js::napi {
6
+
7
+ // Addressof operation
8
+ auto (*handle_addressof)(napi_value handle) noexcept -> void* = nullptr;
9
+
10
+ // Value inspection
11
+ auto (*maybe_fast_is_number_int32)(value_of<number_tag> value) -> std::optional<bool> = nullptr;
12
+ auto (*maybe_fast_is_string_one_byte)(value_of<string_tag> value) -> std::optional<bool> = nullptr;
13
+ auto (*maybe_is_shared_array_buffer)(napi_env env, value_of<object_tag> value) -> std::optional<bool> = nullptr;
14
+
15
+ // nb: These will crash on Bun
16
+ auto has_fast_is_functions = false;
17
+ auto fast_is_array(napi_value value) -> bool;
18
+ auto fast_is_bigint(napi_value value) -> bool;
19
+ auto fast_is_boolean(napi_value value) -> bool;
20
+ auto fast_is_function(napi_value value) -> bool;
21
+ auto fast_is_null(napi_value value) -> bool;
22
+ auto fast_is_number(napi_value value) -> bool;
23
+ auto fast_is_object(napi_value value) -> bool;
24
+ auto fast_is_string(napi_value value) -> bool;
25
+ auto fast_is_undefined(napi_value value) -> bool;
26
+
27
+ // 'SharedArrayBuffer' constructor
28
+ auto (*make_shared_array_buffer)(js::shared_array_buffer::shared_pointer_type data, std::size_t byte_length) -> value_of<shared_array_buffer_tag> = nullptr;
29
+
30
+ // 'ArrayBufferView' constructors
31
+ auto (*make_sab_data_view)(value_of<shared_array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> value_of<data_view_tag> = nullptr;
32
+
33
+ template <class Type>
34
+ using make_sab_typed_array_constructor =
35
+ auto(value_of<shared_array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> value_of<typed_array_tag_of<Type>>;
36
+
37
+ template <class Type>
38
+ make_sab_typed_array_constructor<Type>* make_sab_typed_array_of;
39
+
40
+ template make_sab_typed_array_constructor<double>* make_sab_typed_array_of<double>;
41
+ template make_sab_typed_array_constructor<float>* make_sab_typed_array_of<float>;
42
+ template make_sab_typed_array_constructor<js::float16_t>* make_sab_typed_array_of<js::float16_t>;
43
+ template make_sab_typed_array_constructor<js::uint8_clamped_t>* make_sab_typed_array_of<js::uint8_clamped_t>;
44
+ template make_sab_typed_array_constructor<std::int16_t>* make_sab_typed_array_of<std::int16_t>;
45
+ template make_sab_typed_array_constructor<std::int32_t>* make_sab_typed_array_of<std::int32_t>;
46
+ template make_sab_typed_array_constructor<std::int64_t>* make_sab_typed_array_of<std::int64_t>;
47
+ template make_sab_typed_array_constructor<std::int8_t>* make_sab_typed_array_of<std::int8_t>;
48
+ template make_sab_typed_array_constructor<std::uint16_t>* make_sab_typed_array_of<std::uint16_t>;
49
+ template make_sab_typed_array_constructor<std::uint32_t>* make_sab_typed_array_of<std::uint32_t>;
50
+ template make_sab_typed_array_constructor<std::uint64_t>* make_sab_typed_array_of<std::uint64_t>;
51
+ template make_sab_typed_array_constructor<std::uint8_t>* make_sab_typed_array_of<std::uint8_t>;
52
+
53
+ // Once per process, this detects the host environment (nodejs vs bun)
54
+ auto initialize_host_environment(napi_env env) -> void;
55
+
56
+ } // namespace js::napi
@@ -0,0 +1,42 @@
1
+ import std;
2
+
3
+ // NOLINTBEGIN(bugprone-macro-parentheses)
4
+ #if _WIN64
5
+ // I couldn't get this to work.
6
+ // https://stackoverflow.com/questions/2290587/gcc-style-weak-linking-in-visual-studio
7
+ #define SHIM(NAME)
8
+ #else
9
+ #define SHIM(NAME) \
10
+ __attribute__((weak)) __attribute__((visibility("default"))) auto NAME = nullptr;
11
+ #endif
12
+ // NOLINTEND(bugprone-macro-parentheses)
13
+
14
+ extern "C" {
15
+ const void* shim_nullptr = nullptr;
16
+ // NOLINTBEGIN(bugprone-reserved-identifier)
17
+ SHIM(_ZN2v810Int16Array3NewENS_5LocalINS_17SharedArrayBufferEEEmm)
18
+ SHIM(_ZN2v810Int32Array3NewENS_5LocalINS_17SharedArrayBufferEEEmm)
19
+ SHIM(_ZN2v810Uint8Array3NewENS_5LocalINS_17SharedArrayBufferEEEmm)
20
+ SHIM(_ZN2v811Uint16Array3NewENS_5LocalINS_17SharedArrayBufferEEEmm)
21
+ SHIM(_ZN2v811Uint32Array3NewENS_5LocalINS_17SharedArrayBufferEEEmm)
22
+ SHIM(_ZN2v812BackingStoreD1Ev)
23
+ SHIM(_ZN2v812Float16Array3NewENS_5LocalINS_17SharedArrayBufferEEEmm)
24
+ SHIM(_ZN2v812Float32Array3NewENS_5LocalINS_17SharedArrayBufferEEEmm)
25
+ SHIM(_ZN2v812Float64Array3NewENS_5LocalINS_17SharedArrayBufferEEEmm)
26
+ SHIM(_ZN2v813BigInt64Array3NewENS_5LocalINS_17SharedArrayBufferEEEmm)
27
+ SHIM(_ZN2v814BigUint64Array3NewENS_5LocalINS_17SharedArrayBufferEEEmm)
28
+ SHIM(_ZN2v817SharedArrayBuffer15GetBackingStoreEv)
29
+ SHIM(_ZN2v817SharedArrayBuffer15NewBackingStoreEPvmPFvS1_mS1_ES1_)
30
+ SHIM(_ZN2v817SharedArrayBuffer3NewEPNS_7IsolateENSt3__110shared_ptrINS_12BackingStoreEEE)
31
+ SHIM(_ZN2v817Uint8ClampedArray3NewENS_5LocalINS_17SharedArrayBufferEEEmm)
32
+ SHIM(_ZN2v87Isolate10GetCurrentEv)
33
+ SHIM(_ZN2v88DataView3NewENS_5LocalINS_17SharedArrayBufferEEEmm)
34
+ SHIM(_ZN2v89Int8Array3NewENS_5LocalINS_17SharedArrayBufferEEEmm)
35
+ SHIM(_ZNK2v812BackingStore4DataEv)
36
+ SHIM(_ZNK2v817SharedArrayBuffer10ByteLengthEv)
37
+ SHIM(_ZNK2v85Value7IsInt32Ev)
38
+ SHIM(_ZNK2v85Value8IsNumberEv)
39
+ SHIM(_ZNK2v86String9IsOneByteEv)
40
+ SHIM(node_api_is_sharedarraybuffer)
41
+ // NOLINTEND(bugprone-reserved-identifier)
42
+ }
@@ -13,7 +13,7 @@ class resolver {
13
13
  deferred_{deferred},
14
14
  scheduler_{env.scheduler()},
15
15
  dispatch_{dispatch} {
16
- scheduler_.increment_ref();
16
+ scheduler_.increment_ref(napi_env{env});
17
17
  }
18
18
  resolver(const resolver&) = delete;
19
19
  resolver(resolver&&) = default;
@@ -67,10 +67,9 @@ class resolver {
67
67
  auto schedule(auto operation, auto&&... args) -> void {
68
68
  auto scheduler = std::move(scheduler_);
69
69
  scheduler(
70
- [](napi_env env, napi_deferred deferred, auto operation, auto&&... args) {
70
+ [](napi_env env, napi_value /*nothing*/, napi_deferred deferred, auto operation, auto&&... args) {
71
71
  auto& environment = napi::environment::unsafe_get_environment_as<Environment>(env);
72
- environment.scheduler().decrement_ref();
73
- const auto scope = js::napi::handle_scope{env};
72
+ environment.scheduler().decrement_ref(env);
74
73
  try {
75
74
  auto expected = operation(environment, std::forward<decltype(args)>(args)...);
76
75
  if (expected) {
@@ -88,7 +87,6 @@ class resolver {
88
87
  napi::invoke0(napi_reject_deferred, env, deferred, exception);
89
88
  }
90
89
  },
91
- env_,
92
90
  deferred_,
93
91
  std::move(operation),
94
92
  std::forward<decltype(args)>(args)...
@@ -97,7 +95,7 @@ class resolver {
97
95
 
98
96
  napi_env env_;
99
97
  napi_deferred deferred_;
100
- uv_scheduler scheduler_;
98
+ napi_scheduler scheduler_;
101
99
  Dispatch dispatch_;
102
100
  };
103
101
 
@@ -1,102 +1,27 @@
1
- module;
2
- #include "auto_js/no_unique_address.h"
3
1
  export module napi_js:utility;
2
+ import :support.host;
4
3
  import nodejs;
5
4
  import std;
6
- import util;
7
5
 
8
6
  namespace js::napi {
9
7
 
10
- // See: `v8_enable_direct_handle`.
11
-
12
- // Null handle for both direct and indirect handles
13
- // Note: 1 -> 0x1'0000'0000
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));
17
-
18
- // Unwrap the v8 address of the napi handle. This points into the v8 heap.
19
- // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
20
- struct virtual_handle_address {
21
- protected:
22
- ~virtual_handle_address() = default;
23
-
24
- public:
25
- virtual auto operator()(napi_value value) const noexcept -> void* = 0;
26
- };
27
-
28
- struct direct_handle_address final : virtual_handle_address {
29
- auto operator()(napi_value value) const noexcept -> void* final {
30
- return value;
31
- }
32
- };
33
-
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);
37
- }
38
- };
39
-
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
65
- export class address_equal {
66
- private:
67
- using virtual_equal_type = util::covariant_value<virtual_address_equal, direct_address_equal, indirect_address_equal>;
68
-
69
- public:
70
- explicit address_equal(bool uses_direct_handles) :
71
- equal_{
72
- uses_direct_handles
73
- ? virtual_equal_type{direct_address_equal{}}
74
- : virtual_equal_type{indirect_address_equal{}}
75
- } {}
76
-
8
+ // Equality check for underlying handle. False negatives on primitives.
9
+ struct addressof_equal {
77
10
  auto operator()(napi_value left, napi_value right) const noexcept -> bool {
78
- // NOLINTNEXTLINE(bugprone-exception-escape)
79
- return (*equal_)(left, right);
11
+ return handle_addressof(left) == handle_addressof(right);
80
12
  }
81
-
82
- private:
83
- virtual_equal_type equal_;
84
13
  };
85
14
 
86
15
  // Address hash for napi value handles.
87
- template <class Address>
88
- struct address_hash_of final {
89
- public:
16
+ struct addressof_hash : std::hash<void*> {
17
+ using std::hash<void*>::operator();
90
18
  auto operator()(napi_value value) const noexcept -> std::size_t {
91
- return hash_(address_(value));
19
+ return (*this)(handle_addressof(value));
92
20
  }
93
-
94
- private:
95
- NO_UNIQUE_ADDRESS Address address_;
96
- NO_UNIQUE_ADDRESS std::hash<void*> hash_;
97
21
  };
98
22
 
99
- using direct_address_hash = address_hash_of<direct_handle_address>;
100
- using indirect_address_hash = address_hash_of<indirect_handle_address>;
23
+ // Unordered map for napi values
24
+ template <class Type>
25
+ using unordered_value_map = std::unordered_map<napi_value, Type, addressof_hash, addressof_equal>;
101
26
 
102
27
  } // namespace js::napi
@@ -121,28 +121,7 @@ auto accept_basic_napi_value::operator()(array_buffer_tag /*tag*/, visit_holder
121
121
 
122
122
  auto accept_basic_napi_value::operator()(shared_array_buffer_tag /*tag*/, visit_holder /*visit*/, js::shared_array_buffer&& subject) const
123
123
  -> js::referenceable_value<value_of<shared_array_buffer_tag>> {
124
- auto backing_store = [ & ]() -> auto {
125
- auto byte_length = subject.byte_length();
126
- // v8 does not call the deleter `byte_length` is zero. So the heap-allocated shared_ptr trick
127
- // does not work in that case.
128
- if (byte_length == 0) {
129
- return v8::SharedArrayBuffer::NewBackingStore(nullptr, 0, nullptr, nullptr);
130
- } else {
131
- auto holder = std::make_unique<js::shared_array_buffer::shared_pointer_type>(std::move(subject).acquire_ownership());
132
- auto backing_store = v8::SharedArrayBuffer::NewBackingStore(
133
- holder->get(),
134
- byte_length,
135
- [](void* /*data*/, std::size_t /*length*/, void* param) -> void {
136
- delete static_cast<js::shared_array_buffer::shared_pointer_type*>(param);
137
- },
138
- holder.get()
139
- );
140
- std::ignore = holder.release();
141
- return backing_store;
142
- }
143
- }();
144
- auto shared_array_buffer = v8::SharedArrayBuffer::New(v8::Isolate::GetCurrent(), std::move(backing_store));
145
- auto value = value_of<shared_array_buffer_tag>::from(std::bit_cast<napi_value>(shared_array_buffer));
124
+ auto value = make_shared_array_buffer(std::move(subject).acquire_ownership(), subject.byte_length());
146
125
  return js::referenceable_value{value};
147
126
  }
148
127
 
@@ -1,5 +1,5 @@
1
1
  export module napi_js:accept;
2
- import :container;
2
+ import :utility;
3
3
  import :value;
4
4
  import std;
5
5
  import util;