@auto_js/napi 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/support/host.cc CHANGED
@@ -6,31 +6,45 @@ namespace js::napi {
6
6
  util::lockable_with<bool, {.shared = true}> host_environment_initialized;
7
7
 
8
8
  // Addressof operations
9
- constexpr auto direct_handle_address =
10
- [](napi_value value) noexcept -> void* { return value; };
9
+ constexpr auto direct_handle_address = [](napi_value value) noexcept -> void* { return value; };
10
+ constexpr auto indirect_handle_address = [](napi_value value) noexcept -> void* { return *reinterpret_cast<void**>(value); };
11
11
 
12
- constexpr auto indirect_handle_address =
13
- [](napi_value value) noexcept -> void* { return *reinterpret_cast<void**>(value); };
12
+ // Fast functions which are supported on all platforms
13
+ // nb: Bun exports these v8 functions, but they crash with the `std::bit_cast<v8::Local<T>>` trick.
14
+ auto v8_is_false(napi_env /*env*/, napi_value value) -> bool {
15
+ return std::bit_cast<v8::Local<v8::Value>>(value)->IsFalse();
16
+ }
14
17
 
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
+ auto v8_is_null(napi_env /*env*/, napi_value value) -> bool {
19
+ return std::bit_cast<v8::Local<v8::Value>>(value)->IsNull();
20
+ }
18
21
 
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(); };
22
+ auto v8_is_true(napi_env /*env*/, napi_value value) -> bool {
23
+ return std::bit_cast<v8::Local<v8::Value>>(value)->IsTrue();
24
+ }
21
25
 
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); };
26
+ auto v8_is_undefined(napi_env /*env*/, napi_value value) -> bool {
27
+ return std::bit_cast<v8::Local<v8::Value>>(value)->IsUndefined();
28
+ }
24
29
 
25
- constexpr auto unknown_maybe_fast_is_number_int32 =
26
- [](value_of<number_tag> /*value*/) -> std::optional<bool> { return std::nullopt; };
30
+ auto napi_fast_is_false(napi_env env, napi_value value) -> bool {
31
+ return value == napi::invoke(napi_get_boolean, env, false);
32
+ }
27
33
 
28
- constexpr auto unknown_maybe_fast_is_string_one_byte =
29
- [](value_of<string_tag> /*value*/) -> std::optional<bool> { return std::nullopt; };
34
+ auto napi_fast_is_null(napi_env env, napi_value value) -> bool {
35
+ return value == napi::invoke(napi_get_null, env);
36
+ }
30
37
 
31
- constexpr auto unknown_maybe_is_shared_array_buffer =
32
- [](napi_env /*env*/, value_of<object_tag> /*value*/) -> std::optional<bool> { return std::nullopt; };
38
+ auto napi_fast_is_true(napi_env env, napi_value value) -> bool {
39
+ return value == napi::invoke(napi_get_boolean, env, true);
40
+ }
41
+
42
+ auto napi_fast_is_undefined(napi_env env, napi_value value) -> bool {
43
+ return value == napi::invoke(napi_get_undefined, env);
44
+ }
33
45
 
46
+ // Extended fast functions
47
+ // nb: Bun exports these v8 functions, but they crash with the `std::bit_cast<v8::Local<T>>` trick.
34
48
  auto fast_is_array(napi_value value) -> bool {
35
49
  return std::bit_cast<v8::Local<v8::Value>>(value)->IsArray();
36
50
  }
@@ -39,18 +53,10 @@ auto fast_is_bigint(napi_value value) -> bool {
39
53
  return std::bit_cast<v8::Local<v8::Value>>(value)->IsBigInt();
40
54
  }
41
55
 
42
- auto fast_is_boolean(napi_value value) -> bool {
43
- return std::bit_cast<v8::Local<v8::Value>>(value)->IsBoolean();
44
- }
45
-
46
56
  auto fast_is_function(napi_value value) -> bool {
47
57
  return std::bit_cast<v8::Local<v8::Value>>(value)->IsFunction();
48
58
  }
49
59
 
50
- auto fast_is_null(napi_value value) -> bool {
51
- return std::bit_cast<v8::Local<v8::Value>>(value)->IsNull();
52
- }
53
-
54
60
  auto fast_is_number(napi_value value) -> bool {
55
61
  return std::bit_cast<v8::Local<v8::Value>>(value)->IsNumber();
56
62
  }
@@ -63,13 +69,60 @@ auto fast_is_string(napi_value value) -> bool {
63
69
  return std::bit_cast<v8::Local<v8::Value>>(value)->IsString();
64
70
  }
65
71
 
66
- auto fast_is_undefined(napi_value value) -> bool {
67
- return std::bit_cast<v8::Local<v8::Value>>(value)->IsUndefined();
72
+ // Bug fixes
73
+ auto napi_is_object_array_buffer(napi_env env, local_of<object_tag> value) -> bool {
74
+ return napi::invoke(napi_is_arraybuffer, env, value);
75
+ }
76
+
77
+ auto napi_is_data_block_array_buffer(napi_env env, local_of<data_block_tag> value) -> bool {
78
+ return napi_is_object_array_buffer(env, value);
79
+ }
80
+
81
+ auto bun_is_data_block_array_buffer(napi_env env, local_of<data_block_tag> value) -> bool {
82
+ // https://github.com/oven-sh/bun/issues/32624
83
+ auto* string = napi::invoke(napi_coerce_to_string, env, value);
84
+ auto length = napi::invoke(napi_get_value_string_latin1, env, string, nullptr, 0);
85
+ // '[object ArrayBuffer]'
86
+ return length == 20;
87
+ }
88
+
89
+ auto bun_is_object_array_buffer(napi_env env, local_of<object_tag> value) -> bool {
90
+ if (napi::invoke(napi_is_arraybuffer, env, value)) {
91
+ return bun_is_data_block_array_buffer(env, local_of<data_block_tag>::from(value));
92
+ } else {
93
+ return false;
94
+ }
68
95
  }
69
96
 
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> {
97
+ // Optional value inspectors.
98
+ auto v8_is_number_int32(local_of<number_tag> value) -> std::optional<bool> {
99
+ return std::bit_cast<v8::Local<v8::Number>>(value)->IsInt32();
100
+ };
101
+
102
+ auto v8_is_string_one_byte(local_of<string_tag> value) -> std::optional<bool> {
103
+ return std::bit_cast<v8::Local<v8::String>>(value)->IsOneByte();
104
+ }
105
+
106
+ auto node_api_maybe_is_shared_array_buffer(napi_env env, local_of<object_tag> value) -> std::optional<bool> {
107
+ if constexpr (node_api_has_sharedarraybuffer) {
108
+ return napi::invoke(node_api_is_sharedarraybuffer, env, value);
109
+ } else {
110
+ return std::nullopt;
111
+ }
112
+ }
113
+
114
+ auto bun_maybe_is_shared_array_buffer(napi_env env, local_of<object_tag> value) -> std::optional<bool> {
115
+ if (napi::invoke(napi_is_arraybuffer, env, value)) {
116
+ return !bun_is_data_block_array_buffer(env, local_of<data_block_tag>::from(value));
117
+ } else {
118
+ return std::nullopt;
119
+ }
120
+ }
121
+
122
+ constexpr auto unknown_maybe_is = [](auto...) -> std::optional<bool> { return std::nullopt; };
123
+
124
+ // 'SharedArrayBuffer' functions
125
+ auto v8_make_shared_array_buffer(js::shared_array_buffer::shared_pointer_type data, std::size_t byte_length) -> local_of<shared_array_buffer_tag> {
73
126
  auto backing_store = [ & ]() -> auto {
74
127
  // v8 does not call the deleter `byte_length` is zero. So the heap-allocated shared_ptr trick
75
128
  // does not work in that case.
@@ -90,34 +143,31 @@ constexpr auto v8_make_shared_array_buffer =
90
143
  }
91
144
  }();
92
145
  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));
146
+ return local_of<shared_array_buffer_tag>::from(std::bit_cast<napi_value>(shared_array_buffer));
94
147
  };
95
148
 
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"};
149
+ auto v8_shared_array_buffer_get_byte_length(local_of<shared_array_buffer_tag> buffer) -> std::size_t {
150
+ return std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{buffer})->ByteLength();
151
+ };
152
+
153
+ auto v8_shared_array_buffer_get_backing_store(local_of<shared_array_buffer_tag> buffer) -> std::shared_ptr<std::byte[]> {
154
+ auto backing_store = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(buffer)->GetBackingStore();
155
+ auto* data = reinterpret_cast<std::byte*>(backing_store->Data());
156
+ // NOLINTNEXTLINE(modernize-avoid-c-arrays)
157
+ return std::shared_ptr<std::byte[]>{std::move(backing_store), data};
100
158
  };
101
159
 
102
160
  // '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> {
161
+ // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
162
+ auto v8_make_sab_data_view(local_of<shared_array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> local_of<data_view_tag> {
106
163
  auto buffer_local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{buffer});
107
164
  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"};
165
+ return local_of<data_view_tag>::from(std::bit_cast<napi_value>(view_local));
115
166
  };
116
167
 
117
168
  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>> {
169
+ // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
170
+ auto v8_make_sab_typed_array_of(local_of<shared_array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> local_of<typed_array_tag_of<Type>> {
121
171
  using constructor_type = type_t<util::overloaded{
122
172
  [](std::type_identity<double>) -> std::type_identity<v8::Float64Array> { return {}; },
123
173
  [](std::type_identity<float>) -> std::type_identity<v8::Float32Array> { return {}; },
@@ -134,16 +184,30 @@ constexpr auto v8_make_sab_typed_array_of =
134
184
  }(type<Type>)>;
135
185
  auto buffer_local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{buffer});
136
186
  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));
187
+ return local_of<typed_array_tag_of<Type>>::from(std::bit_cast<napi_value>(view_local));
138
188
  };
139
189
 
140
190
  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>> {
191
+ // NOLINTNEXTLINE(performance-unnecessary-value-param)
192
+ constexpr auto unknown_sab_throw = [](auto...) -> Type {
144
193
  throw js::type_error{u"SharedArrayBuffer is not supported in this environment"};
145
194
  };
146
195
 
196
+ // Dynamic libraries
197
+ constexpr auto node_uv_dlerror =
198
+ [](const uv_lib_t* lib) -> const char* { return uv_dlerror(lib); };
199
+ constexpr auto node_uv_dlopen =
200
+ [](const char* filename, uv_lib_t* lib) -> int { return uv_dlopen(filename, lib); };
201
+ constexpr auto node_uv_dlclose =
202
+ [](uv_lib_t* lib) -> void { uv_dlclose(lib); };
203
+
204
+ constexpr auto unknown_uv_dlerror =
205
+ [](const uv_lib_t* /*lib*/) -> const char* { return "Dynamic libraries are not supported in this environment"; };
206
+ constexpr auto unknown_uv_dlopen =
207
+ [](const char* /*filename*/, uv_lib_t* /*lib*/) -> int { return -1; };
208
+ constexpr auto unknown_uv_dlclose =
209
+ [](uv_lib_t* /*lib*/) -> void { std::unreachable(); };
210
+
147
211
  auto initialize_host_environment(napi_env env) -> void {
148
212
  if (!*host_environment_initialized.read()) {
149
213
  if (auto lock = host_environment_initialized.write(); !*lock) {
@@ -168,44 +232,53 @@ auto initialize_host_environment(napi_env env) -> void {
168
232
  handle_addressof = indirect_handle_address;
169
233
  }
170
234
 
171
- // Detect bun via `process.isBun`
172
- auto is_bun = [ & ] -> bool {
235
+ // Get `globalThis.process`
236
+ auto* process_global = [ & ]() -> napi_value {
173
237
  auto* global = napi::invoke(napi_get_global, env);
174
238
  constexpr auto process_cw = util::make_consteval_string_view(util::cw<"process">);
175
239
  auto* process_str = napi::invoke(node_api_create_property_key_latin1, env, process_cw.data(), process_cw.length());
176
240
  auto* process = napi::invoke(napi_get_property, env, global, process_str);
177
241
  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);
242
+ return process;
183
243
  } else {
244
+ return nullptr;
245
+ }
246
+ }();
247
+
248
+ // Detect bun via `process.isBun`
249
+ auto is_bun = process_global == nullptr ? false : [ & ]() -> bool {
250
+ constexpr auto is_bun_cw = util::make_consteval_string_view(util::cw<"isBun">);
251
+ auto* is_bun_str = napi::invoke(node_api_create_property_key_latin1, env, is_bun_cw.data(), is_bun_cw.length());
252
+ auto* is_bun = napi::invoke(napi_get_property, env, process_global, is_bun_str);
253
+ auto* is_bun_bool = napi::invoke(napi_coerce_to_bool, env, is_bun);
254
+ return napi::invoke(napi_get_value_bool, env, is_bun_bool);
255
+ }();
256
+
257
+ // Detect deno via `process.versions.deno`
258
+ auto is_deno = process_global == nullptr ? false : [ & ]() -> bool {
259
+ constexpr auto versions_cw = util::make_consteval_string_view(util::cw<"versions">);
260
+ auto* versions_str = napi::invoke(node_api_create_property_key_latin1, env, versions_cw.data(), versions_cw.length());
261
+ auto* versions = napi::invoke(napi_get_property, env, process_global, versions_str);
262
+ if (napi::invoke(napi_typeof, env, versions) != napi_object) {
184
263
  return false;
185
264
  }
265
+ constexpr auto deno_cw = util::make_consteval_string_view(util::cw<"deno">);
266
+ auto* deno_str = napi::invoke(node_api_create_property_key_latin1, env, deno_cw.data(), deno_cw.length());
267
+ auto* deno = napi::invoke(napi_get_property, env, versions, deno_str);
268
+ auto* deno_bool = napi::invoke(napi_coerce_to_bool, env, deno);
269
+ return napi::invoke(napi_get_value_bool, env, deno_bool);
186
270
  }();
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;
271
+
272
+ auto is_nodejs = !is_bun && !is_deno;
273
+ if (is_nodejs) {
274
+ has_extended_fast_is_functions = true;
275
+ fast_is_false = v8_is_false;
276
+ fast_is_null = v8_is_null;
277
+ fast_is_true = v8_is_true;
278
+ fast_is_undefined = v8_is_undefined;
279
+ host_uv_dlclose = node_uv_dlclose;
280
+ host_uv_dlerror = node_uv_dlerror;
281
+ host_uv_dlopen = node_uv_dlopen;
209
282
  make_sab_typed_array_of<double> = v8_make_sab_typed_array_of<double>;
210
283
  make_sab_typed_array_of<float> = v8_make_sab_typed_array_of<float>;
211
284
  make_sab_typed_array_of<js::float16_t> = v8_make_sab_typed_array_of<js::float16_t>;
@@ -219,9 +292,49 @@ auto initialize_host_environment(napi_env env) -> void {
219
292
  make_sab_typed_array_of<std::uint64_t> = v8_make_sab_typed_array_of<std::uint64_t>;
220
293
  make_sab_typed_array_of<std::uint8_t> = v8_make_sab_typed_array_of<std::uint8_t>;
221
294
  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;
295
+ maybe_is_number_int32 = v8_is_number_int32;
296
+ maybe_is_shared_array_buffer = node_api_maybe_is_shared_array_buffer;
297
+ maybe_is_string_latin1 = v8_is_string_one_byte;
298
+ shared_array_buffer_get_backing_store = v8_shared_array_buffer_get_backing_store;
299
+ shared_array_buffer_get_byte_length = v8_shared_array_buffer_get_byte_length;
300
+ } else {
301
+ has_extended_fast_is_functions = false;
302
+ fast_is_false = napi_fast_is_false;
303
+ fast_is_null = napi_fast_is_null;
304
+ fast_is_true = napi_fast_is_true;
305
+ fast_is_undefined = napi_fast_is_undefined;
306
+ host_uv_dlclose = unknown_uv_dlclose;
307
+ host_uv_dlerror = unknown_uv_dlerror;
308
+ host_uv_dlopen = unknown_uv_dlopen;
309
+ make_sab_data_view = unknown_sab_throw<local_of<data_view_tag>>;
310
+ make_sab_typed_array_of<double> = unknown_sab_throw<local_of<typed_array_tag_of<double>>>;
311
+ make_sab_typed_array_of<float> = unknown_sab_throw<local_of<typed_array_tag_of<float>>>;
312
+ make_sab_typed_array_of<js::float16_t> = unknown_sab_throw<local_of<typed_array_tag_of<js::float16_t>>>;
313
+ make_sab_typed_array_of<js::uint8_clamped_t> = unknown_sab_throw<local_of<typed_array_tag_of<js::uint8_clamped_t>>>;
314
+ make_sab_typed_array_of<std::int16_t> = unknown_sab_throw<local_of<typed_array_tag_of<std::int16_t>>>;
315
+ make_sab_typed_array_of<std::int32_t> = unknown_sab_throw<local_of<typed_array_tag_of<std::int32_t>>>;
316
+ make_sab_typed_array_of<std::int64_t> = unknown_sab_throw<local_of<typed_array_tag_of<std::int64_t>>>;
317
+ make_sab_typed_array_of<std::int8_t> = unknown_sab_throw<local_of<typed_array_tag_of<std::int8_t>>>;
318
+ make_sab_typed_array_of<std::uint16_t> = unknown_sab_throw<local_of<typed_array_tag_of<std::uint16_t>>>;
319
+ make_sab_typed_array_of<std::uint32_t> = unknown_sab_throw<local_of<typed_array_tag_of<std::uint32_t>>>;
320
+ make_sab_typed_array_of<std::uint64_t> = unknown_sab_throw<local_of<typed_array_tag_of<std::uint64_t>>>;
321
+ make_sab_typed_array_of<std::uint8_t> = unknown_sab_throw<local_of<typed_array_tag_of<std::uint8_t>>>;
322
+ make_shared_array_buffer = unknown_sab_throw<local_of<shared_array_buffer_tag>>;
323
+ maybe_is_number_int32 = unknown_maybe_is;
324
+ maybe_is_shared_array_buffer = unknown_maybe_is;
325
+ maybe_is_string_latin1 = unknown_maybe_is;
326
+ // NOLINTNEXTLINE(modernize-avoid-c-arrays)
327
+ shared_array_buffer_get_backing_store = unknown_sab_throw<std::shared_ptr<std::byte[]>>;
328
+ shared_array_buffer_get_byte_length = unknown_sab_throw<std::size_t>;
329
+ }
330
+
331
+ // Bug fixes
332
+ is_data_block_array_buffer = napi_is_data_block_array_buffer;
333
+ is_object_array_buffer = napi_is_object_array_buffer;
334
+ if (is_bun) {
335
+ is_data_block_array_buffer = bun_is_data_block_array_buffer;
336
+ is_object_array_buffer = bun_is_object_array_buffer;
337
+ maybe_is_shared_array_buffer = bun_maybe_is_shared_array_buffer;
225
338
  }
226
339
  }
227
340
  }
package/support/host.h.cc CHANGED
@@ -1,5 +1,5 @@
1
1
  export module napi_js:support.host;
2
- import :value_handle;
2
+ import :handle.local_of;
3
3
  import std;
4
4
 
5
5
  namespace js::napi {
@@ -7,32 +7,43 @@ namespace js::napi {
7
7
  // Addressof operation
8
8
  auto (*handle_addressof)(napi_value handle) noexcept -> void* = nullptr;
9
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;
10
+ // Fast functions which are supported on all platforms
11
+ auto (*fast_is_false)(napi_env env, napi_value value) -> bool;
12
+ auto (*fast_is_null)(napi_env env, napi_value value) -> bool;
13
+ auto (*fast_is_true)(napi_env env, napi_value value) -> bool;
14
+ auto (*fast_is_undefined)(napi_env env, napi_value value) -> bool;
14
15
 
15
- // nb: These will crash on Bun
16
- auto has_fast_is_functions = false;
16
+ // Extended fast functions
17
+ auto has_extended_fast_is_functions = false;
17
18
  auto fast_is_array(napi_value value) -> bool;
18
19
  auto fast_is_bigint(napi_value value) -> bool;
19
- auto fast_is_boolean(napi_value value) -> bool;
20
20
  auto fast_is_function(napi_value value) -> bool;
21
- auto fast_is_null(napi_value value) -> bool;
22
21
  auto fast_is_number(napi_value value) -> bool;
23
22
  auto fast_is_object(napi_value value) -> bool;
24
23
  auto fast_is_string(napi_value value) -> bool;
25
- auto fast_is_undefined(napi_value value) -> bool;
26
24
 
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;
25
+ // Bug fixes
26
+ auto (*is_object_array_buffer)(napi_env env, local_of<object_tag> value) -> bool = nullptr;
27
+ auto (*is_data_block_array_buffer)(napi_env env, local_of<data_block_tag> value) -> bool = nullptr;
28
+
29
+ // Optional value inspectors. int32 & latin1 will select optimized representations, and
30
+ // shared_array_buffer is required for support of that value type.
31
+ auto (*maybe_is_number_int32)(local_of<number_tag> value) -> std::optional<bool> = nullptr;
32
+ auto (*maybe_is_string_latin1)(local_of<string_tag> value) -> std::optional<bool> = nullptr;
33
+ auto (*maybe_is_shared_array_buffer)(napi_env env, local_of<object_tag> value) -> std::optional<bool> = nullptr;
34
+
35
+ // 'SharedArrayBuffer' functions
36
+ auto (*make_shared_array_buffer)(js::shared_array_buffer::shared_pointer_type data, std::size_t byte_length) -> local_of<shared_array_buffer_tag> = nullptr;
37
+ auto (*shared_array_buffer_get_byte_length)(local_of<shared_array_buffer_tag> buffer) -> std::size_t = nullptr;
38
+ // NOLINTNEXTLINE(modernize-avoid-c-arrays)
39
+ auto (*shared_array_buffer_get_backing_store)(local_of<shared_array_buffer_tag> buffer) -> std::shared_ptr<std::byte[]> = nullptr;
29
40
 
30
41
  // '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;
42
+ auto (*make_sab_data_view)(local_of<shared_array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> local_of<data_view_tag> = nullptr;
32
43
 
33
44
  template <class Type>
34
45
  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>>;
46
+ auto(local_of<shared_array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> local_of<typed_array_tag_of<Type>>;
36
47
 
37
48
  template <class Type>
38
49
  make_sab_typed_array_constructor<Type>* make_sab_typed_array_of;
@@ -50,6 +61,11 @@ template make_sab_typed_array_constructor<std::uint32_t>* make_sab_typed_array_o
50
61
  template make_sab_typed_array_constructor<std::uint64_t>* make_sab_typed_array_of<std::uint64_t>;
51
62
  template make_sab_typed_array_constructor<std::uint8_t>* make_sab_typed_array_of<std::uint8_t>;
52
63
 
64
+ // uv dlfcn wrappers
65
+ auto (*host_uv_dlerror)(const uv_lib_t* lib) -> const char*;
66
+ auto (*host_uv_dlopen)(const char* filename, uv_lib_t* lib) -> int;
67
+ auto (*host_uv_dlclose)(uv_lib_t* lib) -> void;
68
+
53
69
  // Once per process, this detects the host environment (nodejs vs bun)
54
70
  auto initialize_host_environment(napi_env env) -> void;
55
71
 
@@ -34,8 +34,8 @@ class napi_js_module final : private detail::initialize_require {
34
34
  const auto [... indices ] = util::sequence<sizeof...(Args)>;
35
35
  auto& client_environment = environment::make_and_set_environment<Environment>(env, std::get<indices>(std::move(args_))...);
36
36
  // assign export descriptor to napi-constructor namespace object
37
- auto exports_local = value_of<dictionary_tag>::from(exports);
38
- exports_local.assign(client_environment, std::move(make_exports_)(client_environment));
37
+ auto exports_local = local_of<dictionary_tag>::from(exports);
38
+ exports_local->assign(client_environment, std::move(make_exports_)(client_environment));
39
39
  }
40
40
 
41
41
  Make make_exports_;
@@ -19,7 +19,7 @@ class resolver {
19
19
  resolver(resolver&&) = default;
20
20
  ~resolver() {
21
21
  if (scheduler_) {
22
- resolve(std::monostate{});
22
+ resolve(nullptr);
23
23
  }
24
24
  }
25
25
 
@@ -42,7 +42,8 @@ class resolver {
42
42
 
43
43
  // Fulfill using direct resolution value. Note it still needs try/catch (in `fulfill`) because
44
44
  // the `transfer` operation could fail.
45
- auto resolve(auto value) -> void {
45
+ template <class Type>
46
+ auto resolve(Type value) noexcept(std::is_nothrow_move_constructible_v<Type>) -> void {
46
47
  using expected_type = std::expected<decltype(value), js::error_value>;
47
48
  schedule(
48
49
  [](Environment& /*env*/, auto value) -> expected_type {
@@ -53,7 +54,7 @@ class resolver {
53
54
  }
54
55
 
55
56
  // Fulfill using thrown error.
56
- auto reject(js::error_value error) -> void {
57
+ auto reject(js::error_value error) noexcept -> void {
57
58
  using expected_type = std::expected<std::monostate, js::error_value>;
58
59
  schedule(
59
60
  [](Environment& /*env*/, js::error_value error) -> expected_type {
@@ -64,10 +65,11 @@ class resolver {
64
65
  }
65
66
 
66
67
  private:
67
- auto schedule(auto operation, auto&&... args) -> void {
68
+ template <class Operation, class... Args>
69
+ auto schedule(Operation operation, Args&&... args) noexcept(std::is_nothrow_move_constructible_v<Operation> && (std::is_nothrow_move_constructible_v<Args> && ...)) -> void {
68
70
  auto scheduler = std::move(scheduler_);
69
71
  scheduler(
70
- [](napi_env env, napi_value /*nothing*/, napi_deferred deferred, auto operation, auto&&... args) {
72
+ [](napi_env env, napi_value /*nothing*/, napi_deferred deferred, auto operation, auto&&... args) noexcept {
71
73
  auto& environment = napi::environment::unsafe_get_environment_as<Environment>(env);
72
74
  environment.scheduler().decrement_ref(env);
73
75
  try {
@@ -81,10 +83,10 @@ class resolver {
81
83
  }
82
84
  } catch (const napi::pending_error& /*error*/) {
83
85
  auto* exception = napi::invoke(napi_get_and_clear_last_exception, env);
84
- napi::invoke0(napi_reject_deferred, env, deferred, exception);
86
+ napi::invoke0_noexcept(napi_reject_deferred, env, deferred, exception);
85
87
  } catch (const js::error& error) {
86
88
  auto exception = js::transfer_in_strict<napi_value>(error, environment);
87
- napi::invoke0(napi_reject_deferred, env, deferred, exception);
89
+ napi::invoke0_noexcept(napi_reject_deferred, env, deferred, exception);
88
90
  }
89
91
  },
90
92
  deferred_,
@@ -115,7 +117,7 @@ auto make_promise(Environment& env, auto... dispatch) {
115
117
  auto resolve = resolver{env, deferred, std::move(dispatch)...};
116
118
 
117
119
  // `[ promise, resolver ]`
118
- return std::tuple{value_of<promise_tag>::from(promise), std::move(resolve)};
120
+ return std::tuple{local_of<promise_tag>::from(promise), std::move(resolve)};
119
121
  }
120
122
 
121
123
  } // namespace js::napi
@@ -0,0 +1,12 @@
1
+ #define WIN32_LEAN_AND_MEAN
2
+ #include <windows.h>
3
+ #include <delayimp.h>
4
+ import std;
5
+
6
+ const auto __pfnDliNotifyHook2 = PfnDliHook{[](unsigned event, DelayLoadInfo* info) -> FARPROC {
7
+ if (event == dliNotePreLoadLibrary && std::string_view{info->szDll} == "node.exe") {
8
+ return reinterpret_cast<FARPROC>(GetModuleHandle(nullptr));
9
+ } else {
10
+ return nullptr;
11
+ }
12
+ }};