@auto_js/napi 0.0.4 → 0.0.6
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/CMakeLists.txt +12 -7
- package/api/callback_info.cc +8 -3
- package/api/uv_scheduler.h.cc +2 -11
- package/handle/remote.cc +5 -6
- package/handle/types.cc +5 -0
- package/package.json +4 -4
- package/support/callback.cc +3 -3
- package/support/callback_storage.cc +21 -9
- package/support/class_template_storage.cc +0 -10
- package/transfer/accept.cc +4 -3
- package/transfer/accept.h.cc +5 -4
- package/transfer/visit.cc +117 -42
- package/value/array_buffer.cc +12 -4
- package/value/array_buffer.h.cc +19 -5
- package/value/class.cc +1 -1
- package/value/function.cc +4 -4
- package/value/primitive.cc +0 -15
- package/value/primitive.h.cc +0 -3
package/CMakeLists.txt
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
# Locate dependencies (napi_exports is always `nodejs`)
|
|
2
|
+
find_package_from_npm(@auto_js/js AS @auto_js/${AUTO_JS_PREFIX}js PROPAGATE auto_js)
|
|
2
3
|
find_package_from_npm(@auto_js/napi_exports)
|
|
3
|
-
find_package_from_npm(@auto_js/v8_exports)
|
|
4
|
+
find_package_from_npm(@auto_js/v8_exports PROPAGATE google_v8)
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
# Initialize target [napi_js or napi_isolated_js]
|
|
7
|
+
set(napi_js ${AUTO_JS_PREFIX}napi_js)
|
|
8
|
+
add_library(${napi_js} STATIC)
|
|
9
|
+
set_npm_package_properties(@auto_js/napi auto_js napi_js)
|
|
10
|
+
target_compile_features(${napi_js} PUBLIC cxx_std_23)
|
|
11
|
+
target_include_directories(${napi_js} INTERFACE include)
|
|
12
|
+
target_link_libraries(${napi_js} PRIVATE ${auto_js} ${google_v8} utility_js)
|
|
13
|
+
target_link_libraries(${napi_js} PUBLIC nodejs)
|
|
9
14
|
|
|
10
|
-
target_sources(napi_js
|
|
15
|
+
target_sources(${napi_js}
|
|
11
16
|
PRIVATE
|
|
12
17
|
api/uv_dlib.cc
|
|
13
18
|
api/uv_scheduler.cc
|
package/api/callback_info.cc
CHANGED
|
@@ -13,17 +13,22 @@ export struct callback_info : util::non_copyable {
|
|
|
13
13
|
callback_info(napi_env env, napi_callback_info info) {
|
|
14
14
|
napi::invoke0(napi_get_cb_info, env, info, &count_, storage_.data(), &this_, &data_);
|
|
15
15
|
if (count_ > storage_.size()) {
|
|
16
|
-
|
|
16
|
+
constexpr auto message = std::string_view{"Too many arguments provided for a function call"};
|
|
17
|
+
napi::invoke0(napi_throw_range_error, env, nullptr, message.data());
|
|
18
|
+
count_ = 0;
|
|
19
|
+
} else {
|
|
20
|
+
++count_;
|
|
17
21
|
}
|
|
18
22
|
}
|
|
19
23
|
|
|
20
|
-
[[nodiscard]] auto arguments() const -> std::span<const napi_value> { return std::span{storage_}.first(count_); }
|
|
24
|
+
[[nodiscard]] auto arguments() const -> std::span<const napi_value> { return std::span{storage_}.first(count_ - 1); }
|
|
21
25
|
[[nodiscard]] auto data() const -> void* { return data_; }
|
|
22
26
|
[[nodiscard]] auto this_arg() const -> napi_value { return this_; }
|
|
27
|
+
explicit operator bool() const { return count_ != 0; }
|
|
23
28
|
|
|
24
29
|
private:
|
|
25
30
|
napi_value this_;
|
|
26
|
-
std::array<napi_value,
|
|
31
|
+
std::array<napi_value, 16> storage_;
|
|
27
32
|
std::size_t count_{storage_.size()};
|
|
28
33
|
void* data_;
|
|
29
34
|
};
|
package/api/uv_scheduler.h.cc
CHANGED
|
@@ -3,21 +3,12 @@ import :api.uv_handle;
|
|
|
3
3
|
import std;
|
|
4
4
|
import util;
|
|
5
5
|
|
|
6
|
-
#if _LIBCPP_VERSION
|
|
7
|
-
// clang 22.1.0
|
|
8
|
-
// /usr/lib/llvm-22/bin/../include/c++/v1/__new/allocate.h:39:30: error: no matching function for call to 'operator new'
|
|
9
|
-
// 39 | return static_cast<_Tp*>(__builtin_operator_new(__size, static_cast<align_val_t>(__align)));
|
|
10
|
-
export {
|
|
11
|
-
using ::operator new;
|
|
12
|
-
}
|
|
13
|
-
#endif
|
|
14
|
-
|
|
15
6
|
namespace js::napi {
|
|
16
7
|
|
|
17
8
|
// Shareable libuv scheduler
|
|
18
9
|
export class uv_scheduler {
|
|
19
10
|
private:
|
|
20
|
-
using task_type = util::
|
|
11
|
+
using task_type = util::move_only_function<auto()->void>;
|
|
21
12
|
|
|
22
13
|
public:
|
|
23
14
|
auto close(util::function_ref<auto()->void> close_hook) -> void;
|
|
@@ -57,7 +48,7 @@ auto uv_scheduler::operator()(auto task, auto&&... args) const -> void {
|
|
|
57
48
|
auto& async = *async_;
|
|
58
49
|
auto shared = async->shared.write();
|
|
59
50
|
if (shared->is_open) {
|
|
60
|
-
shared->tasks.
|
|
51
|
+
shared->tasks.emplace_back(
|
|
61
52
|
[ task = std::move(task),
|
|
62
53
|
... args = std::forward<decltype(args)>(args) ]() mutable -> void {
|
|
63
54
|
task(std::move(args)...);
|
package/handle/remote.cc
CHANGED
|
@@ -59,12 +59,11 @@ template <class Tag>
|
|
|
59
59
|
auto remote<Tag>::expire(remote* ptr) -> void {
|
|
60
60
|
std::unique_ptr<remote> self{ptr};
|
|
61
61
|
ptr->scheduler_(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
)
|
|
62
|
+
[](auto self) -> void {
|
|
63
|
+
const auto scope = handle_scope{self->env()};
|
|
64
|
+
self.reset();
|
|
65
|
+
},
|
|
66
|
+
std::move(self)
|
|
68
67
|
);
|
|
69
68
|
}
|
|
70
69
|
|
package/handle/types.cc
CHANGED
|
@@ -99,6 +99,11 @@ struct value_specialization<function_tag> : value_defaults<function_tag> {
|
|
|
99
99
|
using value_type = class value_for_function;
|
|
100
100
|
};
|
|
101
101
|
|
|
102
|
+
template <>
|
|
103
|
+
struct value_specialization<data_block_tag> : value_defaults<data_block_tag> {
|
|
104
|
+
using bound_type = class bound_value_for_data_block;
|
|
105
|
+
};
|
|
106
|
+
|
|
102
107
|
template <>
|
|
103
108
|
struct value_specialization<array_buffer_tag> : value_defaults<array_buffer_tag> {
|
|
104
109
|
using bound_type = class bound_value_for_array_buffer;
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@auto_js/napi",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"author": "https://github.com/laverdet/",
|
|
5
5
|
"description": "Automatic JavaScript to N-API bindings",
|
|
6
6
|
"homepage": "https://github.com/laverdet/isolated-vm/tree/experimental/packages/auto_js/napi",
|
|
7
7
|
"license": "ISC",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@auto_js/js": "^0.0.
|
|
10
|
-
"@auto_js/
|
|
11
|
-
"@auto_js/
|
|
9
|
+
"@auto_js/js": "^0.0.6",
|
|
10
|
+
"@auto_js/napi_exports": "^0.0.6",
|
|
11
|
+
"@auto_js/v8_exports": "^0.0.4"
|
|
12
12
|
},
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
package/support/callback.cc
CHANGED
|
@@ -46,7 +46,7 @@ constexpr auto make_free_function(auto function) {
|
|
|
46
46
|
callback,
|
|
47
47
|
std::tuple_cat(
|
|
48
48
|
std::forward_as_tuple(env),
|
|
49
|
-
js::transfer_out<std::tuple<Args
|
|
49
|
+
js::transfer_out<std::tuple<js::functional::parameter_transfer_as_t<Args>...>>(info.arguments(), env)
|
|
50
50
|
)
|
|
51
51
|
);
|
|
52
52
|
}};
|
|
@@ -117,7 +117,7 @@ constexpr auto make_constructor_function(auto constructor) {
|
|
|
117
117
|
callback,
|
|
118
118
|
std::tuple_cat(
|
|
119
119
|
std::forward_as_tuple(env, value_of<object_tag>::from(info.this_arg())),
|
|
120
|
-
js::transfer_out<std::tuple<Args
|
|
120
|
+
js::transfer_out<std::tuple<js::functional::parameter_transfer_as_t<Args>...>>(info.arguments(), env)
|
|
121
121
|
)
|
|
122
122
|
);
|
|
123
123
|
return wrap(std::move(instance));
|
|
@@ -214,7 +214,7 @@ constexpr auto make_member_function(Method method) {
|
|
|
214
214
|
callback,
|
|
215
215
|
std::tuple_cat(
|
|
216
216
|
std::forward_as_tuple(**maybe_that, env),
|
|
217
|
-
js::transfer_out<std::tuple<Args
|
|
217
|
+
js::transfer_out<std::tuple<js::functional::parameter_transfer_as_t<Args>...>>(info.arguments(), env)
|
|
218
218
|
)
|
|
219
219
|
);
|
|
220
220
|
}};
|
|
@@ -22,9 +22,13 @@ auto make_callback_storage(Environment& env, std::invocable<Environment&, const
|
|
|
22
22
|
// Constant expression function, expressed entirely in the type. `data` is the environment.
|
|
23
23
|
const auto callback = napi_callback{[](napi_env nenv, napi_callback_info info) -> napi_value {
|
|
24
24
|
const auto args = callback_info{nenv, info};
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
if (args) {
|
|
26
|
+
auto invoke = function_type{};
|
|
27
|
+
auto& env = *static_cast<Environment*>(args.data());
|
|
28
|
+
return invoke(env, args);
|
|
29
|
+
} else {
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
28
32
|
}};
|
|
29
33
|
return std::tuple{callback, &env};
|
|
30
34
|
} else if constexpr (sizeof(function_type) <= sizeof(void*)) {
|
|
@@ -34,10 +38,14 @@ auto make_callback_storage(Environment& env, std::invocable<Environment&, const
|
|
|
34
38
|
auto* data = reinterpret_cast<void*&>(function);
|
|
35
39
|
const auto callback = napi_callback{[](napi_env nenv, napi_callback_info info) -> napi_value {
|
|
36
40
|
const auto args = callback_info{nenv, info};
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
if (args) {
|
|
42
|
+
auto* data = args.data();
|
|
43
|
+
auto& invoke = reinterpret_cast<function_type&>(data);
|
|
44
|
+
auto& env = *callback_env_local<Environment>;
|
|
45
|
+
return invoke(env, args);
|
|
46
|
+
} else {
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
41
49
|
}};
|
|
42
50
|
return std::tuple{callback, data};
|
|
43
51
|
} else {
|
|
@@ -49,8 +57,12 @@ auto make_callback_storage(Environment& env, std::invocable<Environment&, const
|
|
|
49
57
|
auto external_data = std::make_unique<pair_type>(&env, std::move(function));
|
|
50
58
|
const auto callback = napi_callback{[](napi_env nenv, napi_callback_info info) -> napi_value {
|
|
51
59
|
const auto args = callback_info{nenv, info};
|
|
52
|
-
|
|
53
|
-
|
|
60
|
+
if (args) {
|
|
61
|
+
auto& state = *static_cast<pair_type*>(args.data());
|
|
62
|
+
return state.second(*state.first, args);
|
|
63
|
+
} else {
|
|
64
|
+
return {};
|
|
65
|
+
}
|
|
54
66
|
}};
|
|
55
67
|
return std::tuple{callback, std::move(external_data)};
|
|
56
68
|
}
|
|
@@ -5,16 +5,6 @@ import std;
|
|
|
5
5
|
import util;
|
|
6
6
|
using namespace std::string_literals;
|
|
7
7
|
|
|
8
|
-
#if _LIBCPP_VERSION || _MSVC_STL_UPDATE
|
|
9
|
-
// clang 22.1.0 w/ -stdlib=libc++ (and also MS STL)
|
|
10
|
-
// /workspace/packages/auto_js/napi/support/class_template_storage.cc:28:45: error: invalid operands
|
|
11
|
-
// to binary expression ('basic_string<char>' and 'const std::basic_string_view<char>')
|
|
12
|
-
// 28 | static_assert(index, "Class template '"s + name_sv + "' is missing in storage"s);
|
|
13
|
-
export {
|
|
14
|
-
using std::operator+;
|
|
15
|
-
}
|
|
16
|
-
#endif
|
|
17
|
-
|
|
18
8
|
namespace js::napi {
|
|
19
9
|
|
|
20
10
|
// Given a pack of strings it returns a static reference to a `util::sealed_map` of napi object
|
package/transfer/accept.cc
CHANGED
|
@@ -105,15 +105,16 @@ auto accept_basic_napi_value::operator()(error_tag /*tag*/, visit_holder visit,
|
|
|
105
105
|
// data blocks (array buffer, shared array buffer)
|
|
106
106
|
auto accept_basic_napi_value::operator()(array_buffer_tag /*tag*/, visit_holder /*visit*/, const js::array_buffer& subject) const
|
|
107
107
|
-> js::referenceable_value<value_of<array_buffer_tag>> {
|
|
108
|
+
auto view = std::span<const std::byte>{subject};
|
|
108
109
|
// You could avoid the extra copy for `js::data_block&&` here w/ v8 API. Napi requires the copy
|
|
109
110
|
// though.
|
|
110
111
|
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
|
111
112
|
void* bytes;
|
|
112
|
-
auto* result = napi::invoke(napi_create_arraybuffer, napi_env{*this},
|
|
113
|
+
auto* result = napi::invoke(napi_create_arraybuffer, napi_env{*this}, view.size(), &bytes);
|
|
113
114
|
// nb: `std::memcpy` *technically* results in undefined behavior on block size 0
|
|
114
115
|
// (and also) it maybe causes an infinite loop with musl
|
|
115
116
|
// https://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0
|
|
116
|
-
std::ranges::copy(
|
|
117
|
+
std::ranges::copy(view, static_cast<std::byte*>(bytes));
|
|
117
118
|
auto value = value_of<array_buffer_tag>::from(result);
|
|
118
119
|
return js::referenceable_value{value};
|
|
119
120
|
}
|
|
@@ -121,7 +122,7 @@ auto accept_basic_napi_value::operator()(array_buffer_tag /*tag*/, visit_holder
|
|
|
121
122
|
auto accept_basic_napi_value::operator()(shared_array_buffer_tag /*tag*/, visit_holder /*visit*/, js::shared_array_buffer&& subject) const
|
|
122
123
|
-> js::referenceable_value<value_of<shared_array_buffer_tag>> {
|
|
123
124
|
auto backing_store = [ & ]() -> auto {
|
|
124
|
-
auto byte_length = subject.
|
|
125
|
+
auto byte_length = subject.byte_length();
|
|
125
126
|
// v8 does not call the deleter `byte_length` is zero. So the heap-allocated shared_ptr trick
|
|
126
127
|
// does not work in that case.
|
|
127
128
|
if (byte_length == 0) {
|
package/transfer/accept.h.cc
CHANGED
|
@@ -168,15 +168,16 @@ struct accept_napi_value : accept_basic_napi_value {
|
|
|
168
168
|
// vectors
|
|
169
169
|
auto operator()(this const auto& self, vector_tag /*tag*/, auto& visit, auto&& subject)
|
|
170
170
|
-> js::deferred_receiver<value_of<vector_tag>, decltype(self), decltype(visit), decltype(subject)> {
|
|
171
|
+
auto [... size ] = util::maybe_range_size(subject, 0);
|
|
171
172
|
return {
|
|
172
|
-
value_of<vector_tag>::from(napi::invoke(napi_create_array_with_length, napi_env{self},
|
|
173
|
+
value_of<vector_tag>::from(napi::invoke(napi_create_array_with_length, napi_env{self}, size...)),
|
|
173
174
|
std::forward_as_tuple(self, visit, std::forward<decltype(subject)>(subject)),
|
|
174
175
|
[](value_of<vector_tag> array, auto& self, auto& visit, auto /*&&*/ subject) -> void {
|
|
175
176
|
int ii = 0;
|
|
176
177
|
auto&& range = util::into_range(std::forward<decltype(subject)>(subject));
|
|
177
|
-
for (auto&&
|
|
178
|
-
auto*
|
|
179
|
-
napi::invoke0(napi_set_element, napi_env{self}, napi_value{array}, ii++,
|
|
178
|
+
for (auto&& element : util::forward_range(std::forward<decltype(range)>(range))) {
|
|
179
|
+
auto* item = napi_value{visit(std::forward<decltype(element)>(element), self)};
|
|
180
|
+
napi::invoke0(napi_set_element, napi_env{self}, napi_value{array}, ii++, item);
|
|
180
181
|
}
|
|
181
182
|
},
|
|
182
183
|
};
|
package/transfer/visit.cc
CHANGED
|
@@ -153,48 +153,101 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
|
|
|
153
153
|
|
|
154
154
|
// Check the reference map, and lookup type via napi
|
|
155
155
|
return lookup_or_visit(subject, [ & ]() -> accept_target_t<Accept> {
|
|
156
|
-
auto
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
156
|
+
auto v8_subject = std::bit_cast<v8::Local<v8::Value>>(subject);
|
|
157
|
+
return util::template_traverse(
|
|
158
|
+
accept_tags_of_v<Accept>,
|
|
159
|
+
util::overloaded{
|
|
160
|
+
// Fast paths
|
|
161
|
+
[ & ](undefined_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
162
|
+
return v8_subject->IsUndefined() ? (*this)(value_of<undefined_tag>::from(subject), accept) : next();
|
|
163
|
+
},
|
|
164
|
+
[ & ](null_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
165
|
+
return v8_subject->IsNull() ? (*this)(value_of<null_tag>::from(subject), accept) : next();
|
|
166
|
+
},
|
|
167
|
+
[ & ](boolean_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
168
|
+
return v8_subject->IsBoolean() ? (*this)(value_of<boolean_tag>::from(subject), accept) : next();
|
|
169
|
+
},
|
|
170
|
+
[ & ](number_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
171
|
+
return v8_subject->IsNumber() ? (*this)(value_of<number_tag>::from(subject), accept) : next();
|
|
172
|
+
},
|
|
173
|
+
[ & ](string_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
174
|
+
return v8_subject->IsString() ? immediate(value_of<string_tag>::from(subject), accept) : next();
|
|
175
|
+
},
|
|
176
|
+
[ & ](bigint_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
177
|
+
return v8_subject->IsBigInt() ? immediate(value_of<bigint_tag>::from(subject), accept) : next();
|
|
178
|
+
},
|
|
179
|
+
[ & ](date_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
180
|
+
return v8_subject->IsDate() ? immediate(value_of<date_tag>::from(subject), accept) : next();
|
|
181
|
+
},
|
|
182
|
+
[ & ](list_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
183
|
+
return v8_subject->IsArray() ? immediate(value_of<list_tag>::from(subject), accept) : next();
|
|
184
|
+
},
|
|
185
|
+
[ & ](object_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
186
|
+
// nb: You can't really skip the subsequent is promise, is date, is arraybuffer, etc
|
|
187
|
+
// checks. We don't really want to accept those types here, I don't think..
|
|
188
|
+
return v8_subject->IsObject() ? immediate(value_of<object_tag>::from(subject), accept) : next();
|
|
189
|
+
},
|
|
190
|
+
[ & ](function_tag /*tag*/, auto next) -> accept_target_t<Accept> {
|
|
191
|
+
return v8_subject->IsFunction() ? immediate(value_of<function_tag>::from(subject), accept) : next();
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
// Skip these, otherwise `number_tag` and `string_tag` are invoked twice, which we don't
|
|
195
|
+
// differentiate between.
|
|
196
|
+
[]<class Type>(number_tag_of<Type> /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
|
|
197
|
+
[]<class Type>(string_tag_of<Type> /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
|
|
198
|
+
|
|
199
|
+
// Unknown tag
|
|
200
|
+
[](auto /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
|
|
201
|
+
|
|
202
|
+
// Slow path
|
|
203
|
+
[ & ]() -> accept_target_t<Accept> {
|
|
204
|
+
auto type_of = napi::invoke(napi_typeof, napi_env{*this}, subject);
|
|
205
|
+
switch (type_of) {
|
|
206
|
+
case napi_undefined:
|
|
207
|
+
return (*this)(value_of<undefined_tag>::from(subject), accept);
|
|
208
|
+
case napi_null:
|
|
209
|
+
return (*this)(value_of<null_tag>::from(subject), accept);
|
|
210
|
+
case napi_boolean:
|
|
211
|
+
return (*this)(value_of<boolean_tag>::from(subject), accept);
|
|
212
|
+
case napi_number:
|
|
213
|
+
return (*this)(value_of<number_tag>::from(subject), accept);
|
|
214
|
+
case napi_string:
|
|
215
|
+
return immediate(value_of<string_tag>::from(subject), accept);
|
|
216
|
+
case napi_symbol:
|
|
217
|
+
return immediate(value_of<symbol_tag>::from(subject), accept);
|
|
218
|
+
case napi_object:
|
|
219
|
+
return immediate(value_of<object_tag>::from(subject), accept);
|
|
220
|
+
case napi_function:
|
|
221
|
+
return immediate(value_of<function_tag>::from(subject), accept);
|
|
222
|
+
case napi_external:
|
|
223
|
+
return immediate(value_of<external_tag>::from(subject), accept);
|
|
224
|
+
case napi_bigint:
|
|
225
|
+
return immediate(value_of<bigint_tag>::from(subject), accept);
|
|
188
226
|
}
|
|
227
|
+
std::unreachable();
|
|
228
|
+
},
|
|
229
|
+
}
|
|
230
|
+
);
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
template <class Accept>
|
|
235
|
+
auto operator()(value_of<data_block_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
236
|
+
return lookup_or_visit(subject, [ & ]() -> accept_target_t<Accept> {
|
|
237
|
+
return util::template_traverse(
|
|
238
|
+
accept_tags_of_v<Accept>,
|
|
239
|
+
util::overloaded{
|
|
240
|
+
// Fast paths
|
|
241
|
+
[ & ](data_block_tag /*tag*/, auto /*next*/) -> accept_target_t<Accept> { return accept_tagged(subject, accept); },
|
|
242
|
+
[ & ](array_buffer_tag /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
|
|
243
|
+
[ & ](shared_array_buffer_tag /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
|
|
244
|
+
|
|
245
|
+
// Slow path
|
|
246
|
+
[ & ]() -> accept_target_t<Accept> {
|
|
247
|
+
return immediate(subject, accept);
|
|
189
248
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
case napi_external:
|
|
193
|
-
return immediate(value_of<external_tag>::from(subject), accept);
|
|
194
|
-
case napi_bigint:
|
|
195
|
-
return immediate(value_of<bigint_tag>::from(subject), accept);
|
|
196
|
-
}
|
|
197
|
-
std::unreachable();
|
|
249
|
+
}
|
|
250
|
+
);
|
|
198
251
|
});
|
|
199
252
|
}
|
|
200
253
|
|
|
@@ -206,7 +259,7 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
|
|
|
206
259
|
private:
|
|
207
260
|
// I think this only applies to `symbol_tag`
|
|
208
261
|
template <class Accept, class Tag>
|
|
209
|
-
requires std::
|
|
262
|
+
requires std::is_convertible_v<Tag, primitive_tag>
|
|
210
263
|
auto immediate(value_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
211
264
|
return accept_tagged(subject, accept);
|
|
212
265
|
}
|
|
@@ -227,6 +280,28 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
|
|
|
227
280
|
return accept_tagged(value_of<bigint_tag_of<bigint>>::from(subject), accept);
|
|
228
281
|
}
|
|
229
282
|
|
|
283
|
+
// date
|
|
284
|
+
template <class Accept>
|
|
285
|
+
auto immediate(value_of<object_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
286
|
+
if (napi::invoke(napi_is_array, napi_env{*this}, subject)) {
|
|
287
|
+
return immediate(value_of<list_tag>::from(subject), accept);
|
|
288
|
+
} else if (napi::invoke(napi_is_date, napi_env{*this}, subject)) {
|
|
289
|
+
return immediate(value_of<date_tag>::from(subject), accept);
|
|
290
|
+
} else if (napi::invoke(napi_is_typedarray, napi_env{*this}, subject)) {
|
|
291
|
+
return immediate(value_of<typed_array_tag>::from(subject), accept);
|
|
292
|
+
} else if (napi::invoke(napi_is_dataview, napi_env{*this}, subject)) {
|
|
293
|
+
return immediate(value_of<data_view_tag>::from(subject), accept);
|
|
294
|
+
} else if (std::bit_cast<v8::Local<v8::Object>>(subject)->IsSharedArrayBuffer()) {
|
|
295
|
+
return immediate(value_of<shared_array_buffer_tag>::from(subject), accept);
|
|
296
|
+
} else if (napi::invoke(napi_is_arraybuffer, napi_env{*this}, subject)) {
|
|
297
|
+
return immediate(value_of<array_buffer_tag>::from(subject), accept);
|
|
298
|
+
} else if (napi::invoke(napi_is_promise, napi_env{*this}, subject)) {
|
|
299
|
+
return immediate(value_of<promise_tag>::from(subject), accept);
|
|
300
|
+
} else {
|
|
301
|
+
return immediate(value_of<dictionary_tag>::from(subject), accept);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
230
305
|
// date
|
|
231
306
|
template <class Accept>
|
|
232
307
|
auto immediate(value_of<date_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
@@ -244,7 +319,7 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
|
|
|
244
319
|
}
|
|
245
320
|
|
|
246
321
|
template <class Accept, class Tag>
|
|
247
|
-
requires std::
|
|
322
|
+
requires std::is_convertible_v<Tag, data_block_tag>
|
|
248
323
|
auto immediate(value_of<Tag> subject, const Accept& accept) -> accept_target_t<Accept> {
|
|
249
324
|
return accept_tagged(subject, accept);
|
|
250
325
|
}
|
package/value/array_buffer.cc
CHANGED
|
@@ -6,6 +6,14 @@ import v8;
|
|
|
6
6
|
|
|
7
7
|
namespace js::napi {
|
|
8
8
|
|
|
9
|
+
// `bound_value_for_data_block`
|
|
10
|
+
bound_value_for_data_block::operator std::span<std::byte>() const {
|
|
11
|
+
auto local = std::bit_cast<v8::Local<v8::ArrayBuffer>>(napi_value{*this});
|
|
12
|
+
auto* data = reinterpret_cast<std::byte*>(local->Data());
|
|
13
|
+
auto byte_length = local->ByteLength();
|
|
14
|
+
return std::span{data, byte_length};
|
|
15
|
+
}
|
|
16
|
+
|
|
9
17
|
// `bound_value_for_array_buffer`
|
|
10
18
|
bound_value_for_array_buffer::operator js::array_buffer() const {
|
|
11
19
|
return js::array_buffer{std::span<std::byte>{*this}};
|
|
@@ -17,7 +25,7 @@ bound_value_for_array_buffer::operator std::span<std::byte>() const {
|
|
|
17
25
|
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
|
18
26
|
std::size_t byte_length;
|
|
19
27
|
napi::invoke0(napi_get_arraybuffer_info, env(), napi_value{*this}, &bytes, &byte_length);
|
|
20
|
-
return std::span
|
|
28
|
+
return std::span{reinterpret_cast<std::byte*>(bytes), byte_length};
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
// `bound_value_for_shared_array_buffer`
|
|
@@ -31,7 +39,7 @@ bound_value_for_shared_array_buffer::operator js::shared_array_buffer() const {
|
|
|
31
39
|
|
|
32
40
|
bound_value_for_shared_array_buffer::operator std::span<std::byte>() const {
|
|
33
41
|
auto local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{*this});
|
|
34
|
-
return std::span
|
|
42
|
+
return std::span{reinterpret_cast<std::byte*>(local->Data()), local->ByteLength()};
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
// `value_for_typed_array`
|
|
@@ -56,7 +64,7 @@ auto bound_value_for_typed_array::make_bound(const environment& env, value_of<ty
|
|
|
56
64
|
switch (type_tag) {
|
|
57
65
|
case napi_bigint64_array: return make(typed_array_tag_of<std::int64_t>{});
|
|
58
66
|
case napi_biguint64_array: return make(typed_array_tag_of<std::uint64_t>{});
|
|
59
|
-
case napi_float16_array:
|
|
67
|
+
case napi_float16_array: return make(typed_array_tag_of<js::float16_t>{});
|
|
60
68
|
case napi_float32_array: return make(typed_array_tag_of<float>{});
|
|
61
69
|
case napi_float64_array: return make(typed_array_tag_of<double>{});
|
|
62
70
|
case napi_int16_array: return make(typed_array_tag_of<std::int16_t>{});
|
|
@@ -65,7 +73,7 @@ auto bound_value_for_typed_array::make_bound(const environment& env, value_of<ty
|
|
|
65
73
|
case napi_uint16_array: return make(typed_array_tag_of<std::uint16_t>{});
|
|
66
74
|
case napi_uint32_array: return make(typed_array_tag_of<std::uint32_t>{});
|
|
67
75
|
case napi_uint8_array: return make(typed_array_tag_of<std::uint8_t>{});
|
|
68
|
-
case napi_uint8_clamped_array: return make(typed_array_tag_of<
|
|
76
|
+
case napi_uint8_clamped_array: return make(typed_array_tag_of<js::uint8_clamped_t>{});
|
|
69
77
|
}
|
|
70
78
|
std::unreachable();
|
|
71
79
|
}
|
package/value/array_buffer.h.cc
CHANGED
|
@@ -7,11 +7,21 @@ import v8;
|
|
|
7
7
|
|
|
8
8
|
namespace js::napi {
|
|
9
9
|
|
|
10
|
+
// Data blocks
|
|
11
|
+
class bound_value_for_data_block : public bound_value_next<data_block_tag> {
|
|
12
|
+
public:
|
|
13
|
+
using bound_value_next<data_block_tag>::bound_value_next;
|
|
14
|
+
[[nodiscard]] constexpr auto byte_length() const -> std::size_t { return std::span<std::byte>{*this}.size(); }
|
|
15
|
+
[[nodiscard]] constexpr auto data() const -> const std::byte* { return std::span<std::byte>{*this}.data(); }
|
|
16
|
+
explicit operator std::span<std::byte>() const;
|
|
17
|
+
};
|
|
18
|
+
|
|
10
19
|
// `ArrayBuffer`
|
|
11
20
|
class bound_value_for_array_buffer : public bound_value_next<array_buffer_tag> {
|
|
12
21
|
public:
|
|
13
22
|
using bound_value_next<array_buffer_tag>::bound_value_next;
|
|
14
|
-
|
|
23
|
+
[[nodiscard]] constexpr auto byte_length() const -> std::size_t { return std::span<std::byte>{*this}.size(); }
|
|
24
|
+
[[nodiscard]] constexpr auto data() const -> const std::byte* { return std::span<std::byte>{*this}.data(); }
|
|
15
25
|
explicit operator js::array_buffer() const;
|
|
16
26
|
explicit operator std::span<std::byte>() const;
|
|
17
27
|
};
|
|
@@ -20,7 +30,8 @@ class bound_value_for_array_buffer : public bound_value_next<array_buffer_tag> {
|
|
|
20
30
|
class bound_value_for_shared_array_buffer : public bound_value_next<shared_array_buffer_tag> {
|
|
21
31
|
public:
|
|
22
32
|
using bound_value_next<shared_array_buffer_tag>::bound_value_next;
|
|
23
|
-
|
|
33
|
+
[[nodiscard]] constexpr auto byte_length() const -> std::size_t { return std::span<std::byte>{*this}.size(); }
|
|
34
|
+
[[nodiscard]] constexpr auto data() const -> const std::byte* { return std::span<std::byte>{*this}.data(); }
|
|
24
35
|
explicit operator js::shared_array_buffer() const;
|
|
25
36
|
explicit operator std::span<std::byte>() const;
|
|
26
37
|
};
|
|
@@ -62,7 +73,8 @@ class bound_value_for_typed_array : public bound_value_next<typed_array_tag> {
|
|
|
62
73
|
using any_bound_typed_array = std::variant<
|
|
63
74
|
bound_value<typed_array_tag_of<double>>,
|
|
64
75
|
bound_value<typed_array_tag_of<float>>,
|
|
65
|
-
bound_value<typed_array_tag_of<
|
|
76
|
+
bound_value<typed_array_tag_of<js::float16_t>>,
|
|
77
|
+
bound_value<typed_array_tag_of<js::uint8_clamped_t>>,
|
|
66
78
|
bound_value<typed_array_tag_of<std::int16_t>>,
|
|
67
79
|
bound_value<typed_array_tag_of<std::int32_t>>,
|
|
68
80
|
bound_value<typed_array_tag_of<std::int64_t>>,
|
|
@@ -92,7 +104,8 @@ class value_for_typed_array_of : public value_next<typed_array_tag_of<Type>> {
|
|
|
92
104
|
constexpr auto type_tag = util::overloaded{
|
|
93
105
|
[](std::type_identity<double>) -> napi_typedarray_type { return napi_float64_array; },
|
|
94
106
|
[](std::type_identity<float>) -> napi_typedarray_type { return napi_float32_array; },
|
|
95
|
-
[](std::type_identity<
|
|
107
|
+
[](std::type_identity<js::float16_t>) -> napi_typedarray_type { return napi_float16_array; },
|
|
108
|
+
[](std::type_identity<js::uint8_clamped_t>) -> napi_typedarray_type { return napi_uint8_clamped_array; },
|
|
96
109
|
[](std::type_identity<std::int16_t>) -> napi_typedarray_type { return napi_int16_array; },
|
|
97
110
|
[](std::type_identity<std::int32_t>) -> napi_typedarray_type { return napi_int32_array; },
|
|
98
111
|
[](std::type_identity<std::int64_t>) -> napi_typedarray_type { return napi_bigint64_array; },
|
|
@@ -110,7 +123,8 @@ class value_for_typed_array_of : public value_next<typed_array_tag_of<Type>> {
|
|
|
110
123
|
using constructor_type = type_t<util::overloaded{
|
|
111
124
|
[](std::type_identity<double>) -> std::type_identity<v8::Float64Array> { return {}; },
|
|
112
125
|
[](std::type_identity<float>) -> std::type_identity<v8::Float32Array> { return {}; },
|
|
113
|
-
[](std::type_identity<
|
|
126
|
+
[](std::type_identity<js::float16_t>) -> std::type_identity<v8::Float16Array> { return {}; },
|
|
127
|
+
[](std::type_identity<js::uint8_clamped_t>) -> std::type_identity<v8::Uint8ClampedArray> { return {}; },
|
|
114
128
|
[](std::type_identity<std::int16_t>) -> std::type_identity<v8::Int16Array> { return {}; },
|
|
115
129
|
[](std::type_identity<std::int32_t>) -> std::type_identity<v8::Int32Array> { return {}; },
|
|
116
130
|
[](std::type_identity<std::int64_t>) -> std::type_identity<v8::BigInt64Array> { return {}; },
|
package/value/class.cc
CHANGED
|
@@ -37,7 +37,7 @@ template <class Type>
|
|
|
37
37
|
template <class... Args>
|
|
38
38
|
auto value_for_class_of<Type>::transfer_construct(auto& env, auto instance, std::tuple<Args...> runtime_args) const -> value_of<object_tag> {
|
|
39
39
|
using element_type = decltype(instance)::element_type;
|
|
40
|
-
auto construct = [ & ](napi_value this_arg)
|
|
40
|
+
auto construct = [ & ](napi_value this_arg) -> napi_value {
|
|
41
41
|
// Tag `this_arg`
|
|
42
42
|
napi::invoke0(napi_type_tag_object, napi_env{env}, this_arg, &type_tag_for<element_type>);
|
|
43
43
|
|
package/value/function.cc
CHANGED
|
@@ -6,14 +6,14 @@ namespace js::napi {
|
|
|
6
6
|
|
|
7
7
|
template <class Result>
|
|
8
8
|
auto value_for_function::apply(auto_environment auto& env, auto&& args) -> Result {
|
|
9
|
-
auto
|
|
10
|
-
return invoke<Result>(env, std::span{
|
|
9
|
+
auto argv = js::transfer_in_strict<std::vector<napi_value>>(std::forward<decltype(args)>(args), env);
|
|
10
|
+
return invoke<Result>(env, std::span{argv});
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
template <class Result>
|
|
14
14
|
auto value_for_function::call(auto_environment auto& env, auto&&... args) -> Result {
|
|
15
|
-
auto
|
|
16
|
-
return invoke<Result>(env, std::span{
|
|
15
|
+
auto argv = js::transfer_in_strict<std::array<napi_value, sizeof...(args)>>(std::forward_as_tuple(args...), env);
|
|
16
|
+
return invoke<Result>(env, std::span{argv});
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
template <class Result>
|
package/value/primitive.cc
CHANGED
|
@@ -20,14 +20,6 @@ bound_value_for_number::operator std::int32_t() const {
|
|
|
20
20
|
return napi::invoke(napi_get_value_int32, env(), napi_value{*this});
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
bound_value_for_number::operator std::int64_t() const {
|
|
24
|
-
return napi::invoke(napi_get_value_int64, env(), napi_value{*this});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
bound_value_for_number::operator std::uint32_t() const {
|
|
28
|
-
return napi::invoke(napi_get_value_uint32, env(), napi_value{*this});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
23
|
// bigint
|
|
32
24
|
bound_value_for_bigint::operator bigint() const {
|
|
33
25
|
js::bigint value;
|
|
@@ -55,13 +47,6 @@ bound_value_for_bigint::operator std::int64_t() const {
|
|
|
55
47
|
return value;
|
|
56
48
|
}
|
|
57
49
|
|
|
58
|
-
bound_value_for_bigint::operator std::uint64_t() const {
|
|
59
|
-
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
|
60
|
-
std::uint64_t value;
|
|
61
|
-
napi::invoke(napi_get_value_bigint_uint64, env(), napi_value{*this}, &value);
|
|
62
|
-
return value;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
50
|
// string
|
|
66
51
|
bound_value_for_string::operator std::string() const {
|
|
67
52
|
std::string string;
|
package/value/primitive.h.cc
CHANGED
|
@@ -19,8 +19,6 @@ class bound_value_for_number : public bound_value_next<number_tag> {
|
|
|
19
19
|
using bound_value_next<number_tag>::bound_value_next;
|
|
20
20
|
[[nodiscard]] explicit operator double() const;
|
|
21
21
|
[[nodiscard]] explicit operator std::int32_t() const;
|
|
22
|
-
[[nodiscard]] explicit operator std::int64_t() const;
|
|
23
|
-
[[nodiscard]] explicit operator std::uint32_t() const;
|
|
24
22
|
};
|
|
25
23
|
|
|
26
24
|
// bigint
|
|
@@ -29,7 +27,6 @@ class bound_value_for_bigint : public bound_value_next<bigint_tag> {
|
|
|
29
27
|
using bound_value_next<bigint_tag>::bound_value_next;
|
|
30
28
|
[[nodiscard]] explicit operator bigint() const;
|
|
31
29
|
[[nodiscard]] explicit operator std::int64_t() const;
|
|
32
|
-
[[nodiscard]] explicit operator std::uint64_t() const;
|
|
33
30
|
};
|
|
34
31
|
|
|
35
32
|
// string
|