@auto_js/napi 0.0.1 → 0.0.2
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 +10 -4
- package/README.md +30 -3
- package/_module.cc +12 -10
- package/api/api.cc +8 -7
- package/api/callback_info.cc +1 -7
- package/api/finalizer.cc +1 -4
- package/api/invoke.cc +4 -9
- package/api/uv_dlib.cc +27 -0
- package/api/uv_dlib.h.cc +21 -0
- package/api/uv_handle.cc +9 -9
- package/api/uv_scheduler.cc +11 -17
- package/api/uv_scheduler.h.cc +3 -6
- package/handle/bound_value.cc +4 -7
- package/handle/reference.cc +9 -5
- package/handle/remote.cc +11 -17
- package/handle/types.cc +61 -46
- package/handle/value.cc +12 -14
- package/package.json +7 -6
- package/support/callback.cc +7 -19
- package/support/callback_storage.cc +4 -9
- package/support/class_template_storage.cc +4 -6
- package/support/container.cc +9 -10
- package/support/environment.cc +32 -20
- package/support/environment.h.cc +8 -18
- package/support/environment_fwd.cc +1 -2
- package/support/error_scope.cc +0 -2
- package/support/initialize.h.cc +2 -5
- package/support/promise.cc +3 -10
- package/support/string_table.cc +3 -5
- package/support/utility.cc +54 -28
- package/transfer/accept.cc +131 -327
- package/transfer/accept.h.cc +390 -0
- package/transfer/visit.cc +201 -132
- package/value/array.cc +1 -3
- package/value/array.h.cc +5 -11
- package/value/array_buffer.cc +109 -0
- package/value/array_buffer.h.cc +150 -0
- package/value/class.cc +12 -21
- package/value/class.h.cc +5 -10
- package/value/external.cc +6 -10
- package/value/function.cc +5 -12
- package/value/function.h.cc +2 -9
- package/value/object.cc +2 -6
- package/value/object.h.cc +7 -15
- package/value/primitive.cc +12 -81
- package/value/primitive.h.cc +6 -64
- package/value/record.cc +38 -0
- package/value/record.h.cc +39 -0
- package/value/value.cc +8 -8
- package/value/dictionary.cc +0 -33
- package/value/dictionary.h.cc +0 -56
package/handle/types.cc
CHANGED
|
@@ -4,7 +4,7 @@ import nodejs;
|
|
|
4
4
|
|
|
5
5
|
namespace js::napi {
|
|
6
6
|
|
|
7
|
-
// `value_handle` is the base class of `
|
|
7
|
+
// `value_handle` is the base class of `value_of<T>`, and `bound_value<T>`.
|
|
8
8
|
class value_handle {
|
|
9
9
|
protected:
|
|
10
10
|
explicit value_handle(napi_value value) :
|
|
@@ -24,9 +24,9 @@ class value_handle {
|
|
|
24
24
|
napi_value value_{};
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
-
// `
|
|
27
|
+
// `value_of` forward declarations
|
|
28
28
|
export template <class Tag = value_tag>
|
|
29
|
-
class
|
|
29
|
+
class value_of;
|
|
30
30
|
|
|
31
31
|
template <class Tag>
|
|
32
32
|
class value_next;
|
|
@@ -34,60 +34,52 @@ class value_next;
|
|
|
34
34
|
template <class Type>
|
|
35
35
|
class value_for_class_of;
|
|
36
36
|
|
|
37
|
+
template <class Type>
|
|
38
|
+
class value_for_typed_array_of;
|
|
39
|
+
|
|
37
40
|
// `bound_value` forward declarations
|
|
38
|
-
|
|
41
|
+
template <class Tag>
|
|
39
42
|
class bound_value;
|
|
40
43
|
|
|
41
44
|
template <class Tag>
|
|
42
45
|
class bound_value_next;
|
|
43
46
|
|
|
44
|
-
|
|
47
|
+
template <class Type>
|
|
48
|
+
class bound_value_for_typed_array_of;
|
|
49
|
+
|
|
50
|
+
// Map of `value_of<Tag>` / `bound_value<Tag>` to concrete implementation classes.
|
|
45
51
|
template <class Tag>
|
|
46
|
-
struct
|
|
52
|
+
struct value_defaults {
|
|
47
53
|
using value_type = value_next<Tag>;
|
|
48
54
|
using bound_type = bound_value_next<Tag>;
|
|
49
55
|
};
|
|
50
56
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
struct value_specialization<undefined_tag> {
|
|
54
|
-
using value_type = class value_for_undefined;
|
|
55
|
-
using bound_type = bound_value_next<undefined_tag>;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
template <>
|
|
59
|
-
struct value_specialization<null_tag> {
|
|
60
|
-
using value_type = class value_for_null;
|
|
61
|
-
using bound_type = bound_value_next<null_tag>;
|
|
62
|
-
};
|
|
57
|
+
template <class Tag>
|
|
58
|
+
struct value_specialization : value_defaults<Tag> {};
|
|
63
59
|
|
|
60
|
+
// Typed specializations
|
|
64
61
|
template <>
|
|
65
|
-
struct value_specialization<boolean_tag> {
|
|
66
|
-
using value_type = class value_for_boolean;
|
|
62
|
+
struct value_specialization<boolean_tag> : value_defaults<boolean_tag> {
|
|
67
63
|
using bound_type = class bound_value_for_boolean;
|
|
68
64
|
};
|
|
69
65
|
|
|
70
66
|
template <>
|
|
71
|
-
struct value_specialization<number_tag> {
|
|
72
|
-
using value_type = class value_for_number;
|
|
67
|
+
struct value_specialization<number_tag> : value_defaults<number_tag> {
|
|
73
68
|
using bound_type = class bound_value_for_number;
|
|
74
69
|
};
|
|
75
70
|
|
|
76
71
|
template <>
|
|
77
|
-
struct value_specialization<bigint_tag> {
|
|
78
|
-
using value_type = class value_for_bigint;
|
|
72
|
+
struct value_specialization<bigint_tag> : value_defaults<bigint_tag> {
|
|
79
73
|
using bound_type = class bound_value_for_bigint;
|
|
80
74
|
};
|
|
81
75
|
|
|
82
76
|
template <>
|
|
83
|
-
struct value_specialization<string_tag> {
|
|
84
|
-
using value_type = class value_for_string;
|
|
77
|
+
struct value_specialization<string_tag> : value_defaults<string_tag> {
|
|
85
78
|
using bound_type = class bound_value_for_string;
|
|
86
79
|
};
|
|
87
80
|
|
|
88
81
|
template <>
|
|
89
|
-
struct value_specialization<date_tag> {
|
|
90
|
-
using value_type = class value_for_date;
|
|
82
|
+
struct value_specialization<date_tag> : value_defaults<date_tag> {
|
|
91
83
|
using bound_type = class bound_value_for_date;
|
|
92
84
|
};
|
|
93
85
|
|
|
@@ -98,39 +90,62 @@ struct value_specialization<object_tag> {
|
|
|
98
90
|
};
|
|
99
91
|
|
|
100
92
|
template <>
|
|
101
|
-
struct value_specialization<
|
|
93
|
+
struct value_specialization<record_tag> : value_defaults<record_tag> {
|
|
94
|
+
using bound_type = class bound_value_for_record;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
template <>
|
|
98
|
+
struct value_specialization<function_tag> : value_defaults<function_tag> {
|
|
102
99
|
using value_type = class value_for_function;
|
|
103
|
-
using bound_type = bound_value_next<function_tag>;
|
|
104
100
|
};
|
|
105
101
|
|
|
106
|
-
template
|
|
107
|
-
struct value_specialization<
|
|
108
|
-
using
|
|
109
|
-
using bound_type = bound_value_next<class_tag_of<Type>>;
|
|
102
|
+
template <>
|
|
103
|
+
struct value_specialization<array_buffer_tag> : value_defaults<array_buffer_tag> {
|
|
104
|
+
using bound_type = class bound_value_for_array_buffer;
|
|
110
105
|
};
|
|
111
106
|
|
|
112
107
|
template <>
|
|
113
|
-
struct value_specialization<
|
|
114
|
-
using
|
|
115
|
-
using bound_type = class bound_value_for_external;
|
|
108
|
+
struct value_specialization<shared_array_buffer_tag> : value_defaults<shared_array_buffer_tag> {
|
|
109
|
+
using bound_type = class bound_value_for_shared_array_buffer;
|
|
116
110
|
};
|
|
117
111
|
|
|
118
112
|
template <>
|
|
119
|
-
struct value_specialization<
|
|
120
|
-
using
|
|
121
|
-
|
|
113
|
+
struct value_specialization<array_buffer_view_tag> : value_defaults<array_buffer_view_tag> {
|
|
114
|
+
using bound_type = class bound_value_for_array_buffer_view;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
template <>
|
|
118
|
+
struct value_specialization<typed_array_tag> {
|
|
119
|
+
using value_type = class value_for_typed_array;
|
|
120
|
+
using bound_type = class bound_value_for_typed_array;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
template <class Type>
|
|
124
|
+
struct value_specialization<typed_array_tag_of<Type>> {
|
|
125
|
+
using value_type = value_for_typed_array_of<Type>;
|
|
126
|
+
using bound_type = bound_value_for_typed_array_of<Type>;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
template <>
|
|
130
|
+
struct value_specialization<data_view_tag> {
|
|
131
|
+
using value_type = class value_for_data_view;
|
|
132
|
+
using bound_type = class bound_value_for_data_view;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
template <class Type>
|
|
136
|
+
struct value_specialization<class_tag_of<Type>> : value_defaults<class_tag_of<Type>> {
|
|
137
|
+
using value_type = value_for_class_of<Type>;
|
|
122
138
|
};
|
|
123
139
|
|
|
124
140
|
template <>
|
|
125
|
-
struct value_specialization<
|
|
126
|
-
using value_type =
|
|
127
|
-
using bound_type = class
|
|
141
|
+
struct value_specialization<external_tag> {
|
|
142
|
+
using value_type = class value_for_external;
|
|
143
|
+
using bound_type = class bound_value_for_external;
|
|
128
144
|
};
|
|
129
145
|
|
|
130
146
|
template <>
|
|
131
|
-
struct value_specialization<
|
|
132
|
-
using
|
|
133
|
-
using bound_type = class bound_value_for_dictionary;
|
|
147
|
+
struct value_specialization<vector_tag> : value_defaults<vector_tag> {
|
|
148
|
+
using bound_type = class bound_value_for_vector;
|
|
134
149
|
};
|
|
135
150
|
|
|
136
151
|
} // namespace js::napi
|
package/handle/value.cc
CHANGED
|
@@ -1,52 +1,50 @@
|
|
|
1
|
-
module;
|
|
2
|
-
#include <concepts>
|
|
3
|
-
#include <type_traits>
|
|
4
1
|
export module napi_js:value_handle;
|
|
5
2
|
import :handle.types;
|
|
6
3
|
import auto_js;
|
|
7
4
|
import nodejs;
|
|
5
|
+
import std;
|
|
8
6
|
|
|
9
7
|
namespace js::napi {
|
|
10
8
|
|
|
11
9
|
// Heirarchy:
|
|
12
|
-
//
|
|
10
|
+
// value_of<object_tag> ->
|
|
13
11
|
// value_for_object ->
|
|
14
12
|
// value_next<object_tag> ->
|
|
15
|
-
//
|
|
13
|
+
// value_of<value_tag> -> ...
|
|
16
14
|
|
|
17
|
-
// Details applied to each level of the `
|
|
15
|
+
// Details applied to each level of the `value_of<T>` hierarchy.
|
|
18
16
|
template <class Tag>
|
|
19
|
-
class value_next : public
|
|
17
|
+
class value_next : public value_of<typename Tag::tag_type> {
|
|
20
18
|
public:
|
|
21
|
-
using
|
|
19
|
+
using value_of<typename Tag::tag_type>::value_of;
|
|
22
20
|
|
|
23
21
|
// "Downcast" to a more specific tag. Potentially unsafe.
|
|
24
22
|
template <std::convertible_to<Tag> To>
|
|
25
|
-
auto cast(To /*tag*/) const ->
|
|
23
|
+
auto cast(To /*tag*/) const -> value_of<To> { return value_of<To>::from(*this); }
|
|
26
24
|
|
|
27
25
|
// Construct from any `napi_value`. Potentially unsafe.
|
|
28
|
-
static auto from(napi_value value_) ->
|
|
26
|
+
static auto from(napi_value value_) -> value_of<Tag> { return std::bit_cast<value_of<Tag>>(value_); }
|
|
29
27
|
};
|
|
30
28
|
|
|
31
29
|
// Tagged napi_value
|
|
32
30
|
export template <class Tag>
|
|
33
|
-
class
|
|
31
|
+
class value_of : public value_specialization<Tag>::value_type {
|
|
34
32
|
public:
|
|
35
33
|
using value_specialization<Tag>::value_type::value_type;
|
|
36
34
|
};
|
|
37
35
|
|
|
38
36
|
// Sentinel instantiation
|
|
39
37
|
template <>
|
|
40
|
-
class
|
|
38
|
+
class value_of<void> : public value_handle {
|
|
41
39
|
public:
|
|
42
40
|
using value_handle::value_handle;
|
|
43
41
|
};
|
|
44
42
|
|
|
45
43
|
} // namespace js::napi
|
|
46
44
|
|
|
47
|
-
// Specialize for `js::forward`. Makes `js::forward{
|
|
45
|
+
// Specialize for `js::forward`. Makes `js::forward{value_of<Tag>}` infer
|
|
48
46
|
// `js::forward<Tag, ...>`.
|
|
49
47
|
namespace js {
|
|
50
48
|
template <class Tag>
|
|
51
|
-
struct
|
|
49
|
+
struct forward_tag_for<napi::value_of<Tag>> : std::type_identity<Tag> {};
|
|
52
50
|
} // namespace js
|
package/package.json
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@auto_js/napi",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Automatic JavaScript to N-API bindings",
|
|
3
|
+
"version": "0.0.2",
|
|
5
4
|
"author": "https://github.com/laverdet/",
|
|
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
|
+
"dependencies": {
|
|
9
|
+
"@auto_js/js": "^0.0.2",
|
|
10
|
+
"@auto_js/v8_exports": "^0.0.2",
|
|
11
|
+
"@auto_js/napi_exports": "^0.0.2"
|
|
12
|
+
},
|
|
8
13
|
"repository": {
|
|
9
14
|
"type": "git",
|
|
10
15
|
"url": "git+https://github.com/laverdet/isolated-vm.git"
|
|
11
|
-
},
|
|
12
|
-
"dependencies": {
|
|
13
|
-
"@auto_js/js": "0.0.1",
|
|
14
|
-
"@auto_js/napi_exports": "0.0.1"
|
|
15
16
|
}
|
|
16
17
|
}
|
package/support/callback.cc
CHANGED
|
@@ -1,20 +1,10 @@
|
|
|
1
|
-
module;
|
|
2
|
-
#include <optional>
|
|
3
|
-
#include <tuple>
|
|
4
|
-
#include <type_traits>
|
|
5
|
-
#include <utility>
|
|
6
1
|
export module napi_js:callback;
|
|
7
2
|
export import :callback_storage;
|
|
8
|
-
import :api;
|
|
9
|
-
import :bound_value;
|
|
10
|
-
import :environment_fwd;
|
|
11
3
|
import :error_scope;
|
|
12
|
-
import
|
|
13
|
-
import :value_handle;
|
|
4
|
+
import std;
|
|
14
5
|
import util;
|
|
15
6
|
|
|
16
7
|
namespace js::napi {
|
|
17
|
-
namespace {
|
|
18
8
|
|
|
19
9
|
// Unwrap `this` into the correct tagged external. Returns `std::nullopt` if there was a type error,
|
|
20
10
|
// and there is a napi exception pending. `nullptr` will not be returned.
|
|
@@ -23,7 +13,7 @@ template <class Type>
|
|
|
23
13
|
constexpr auto unwrap_member_this = [](auto_environment auto& env, napi_value this_arg) noexcept -> std::optional<tagged_external<Type>> {
|
|
24
14
|
return napi::invoke_maybe(napi_coerce_to_object, napi_env{env}, this_arg)
|
|
25
15
|
.and_then([ &env ](napi_value coerced_this_arg) -> std::optional<tagged_external<Type>> {
|
|
26
|
-
auto as_object = bound_value{env,
|
|
16
|
+
auto as_object = bound_value{env, value_of<object_tag>::from(coerced_this_arg)};
|
|
27
17
|
// Technically `try_cast` can throw but it should only be in catastrophic cases.
|
|
28
18
|
Type* unwrapped = as_object.try_cast(type<Type>);
|
|
29
19
|
if (unwrapped == nullptr) {
|
|
@@ -36,13 +26,11 @@ constexpr auto unwrap_member_this = [](auto_environment auto& env, napi_value th
|
|
|
36
26
|
});
|
|
37
27
|
};
|
|
38
28
|
|
|
39
|
-
} // namespace
|
|
40
|
-
|
|
41
29
|
// Function type for internal host object construction
|
|
42
30
|
using internal_constructor = util::function_ref<auto(napi_value)->napi_value>;
|
|
43
31
|
|
|
44
32
|
// Make callback for plain free function
|
|
45
|
-
|
|
33
|
+
template <auto_environment Environment>
|
|
46
34
|
constexpr auto make_free_function(auto function) {
|
|
47
35
|
constexpr auto make_with_try_catch =
|
|
48
36
|
[]<class Env, class... Args, bool Nx, class Result>(
|
|
@@ -92,7 +80,7 @@ constexpr auto make_free_function(auto function) {
|
|
|
92
80
|
}
|
|
93
81
|
|
|
94
82
|
// Make callback for constructor invocations
|
|
95
|
-
|
|
83
|
+
template <auto_environment Environment, class Type>
|
|
96
84
|
constexpr auto make_constructor_function(auto constructor) {
|
|
97
85
|
// First, a lambda is created which will actually invoke the supplied constructor function.
|
|
98
86
|
constexpr auto make_invoke_runtime_constructor = util::overloaded{
|
|
@@ -128,7 +116,7 @@ constexpr auto make_constructor_function(auto constructor) {
|
|
|
128
116
|
auto instance = std::apply(
|
|
129
117
|
callback,
|
|
130
118
|
std::tuple_cat(
|
|
131
|
-
std::forward_as_tuple(env,
|
|
119
|
+
std::forward_as_tuple(env, value_of<object_tag>::from(info.this_arg())),
|
|
132
120
|
js::transfer_out<std::tuple<Args...>>(info.arguments(), env)
|
|
133
121
|
)
|
|
134
122
|
);
|
|
@@ -148,7 +136,7 @@ constexpr auto make_constructor_function(auto constructor) {
|
|
|
148
136
|
using callback_type = decltype(callback);
|
|
149
137
|
return util::bind{
|
|
150
138
|
[](callback_type& callback, Environment& env, const callback_info& info) noexcept -> napi_value {
|
|
151
|
-
return wrap(callback(env,
|
|
139
|
+
return wrap(callback(env, value_of<object_tag>::from(info.this_arg())));
|
|
152
140
|
},
|
|
153
141
|
std::move(callback),
|
|
154
142
|
};
|
|
@@ -206,7 +194,7 @@ constexpr auto make_constructor_function(auto constructor) {
|
|
|
206
194
|
};
|
|
207
195
|
|
|
208
196
|
// Make callback for method invocations
|
|
209
|
-
|
|
197
|
+
template <auto_environment Environment, class Type, class Method>
|
|
210
198
|
constexpr auto make_member_function(Method method) {
|
|
211
199
|
constexpr auto make_with_try_catch =
|
|
212
200
|
[]<class That, class Env, class... Args, bool Nx, class Result>(
|
|
@@ -1,20 +1,15 @@
|
|
|
1
|
-
module;
|
|
2
|
-
#include <memory>
|
|
3
|
-
#include <type_traits>
|
|
4
|
-
#include <utility>
|
|
5
1
|
export module napi_js:callback_storage;
|
|
6
2
|
import :api;
|
|
7
3
|
import :environment_fwd;
|
|
4
|
+
import std;
|
|
8
5
|
|
|
9
6
|
namespace js::napi {
|
|
10
7
|
|
|
11
|
-
namespace {
|
|
12
8
|
// Since napi runs each environment in its own thread we can store the environment data pointer
|
|
13
9
|
// here. We could also go through `napi_get_instance_data` but there is no assurance that the
|
|
14
10
|
// pointer type is the same. We assume the environment pointer will outlive the callback.
|
|
15
11
|
template <auto_environment Environment>
|
|
16
|
-
thread_local Environment*
|
|
17
|
-
} // namespace
|
|
12
|
+
thread_local Environment* callback_env_local = nullptr;
|
|
18
13
|
|
|
19
14
|
// Converts any invocable into a `napi_callback` and data pointer for use in napi API calls. The
|
|
20
15
|
// result is a `std::tuple` with `{ callback_ptr, data_ptr, finalizer }`. Finalizer is either a
|
|
@@ -35,13 +30,13 @@ auto make_callback_storage(Environment& env, std::invocable<Environment&, const
|
|
|
35
30
|
} else if constexpr (sizeof(function_type) <= sizeof(void*)) {
|
|
36
31
|
// Trivial function type containing less than or equal to a pointer size. `data` is the
|
|
37
32
|
// function and environment is stored in a thread local.
|
|
38
|
-
|
|
33
|
+
callback_env_local<Environment> = &env;
|
|
39
34
|
auto* data = reinterpret_cast<void*&>(function);
|
|
40
35
|
const auto callback = napi_callback{[](napi_env nenv, napi_callback_info info) -> napi_value {
|
|
41
36
|
const auto args = callback_info{nenv, info};
|
|
42
37
|
auto* data = args.data();
|
|
43
38
|
auto& invoke = reinterpret_cast<function_type&>(data);
|
|
44
|
-
auto& env = *
|
|
39
|
+
auto& env = *callback_env_local<Environment>;
|
|
45
40
|
return invoke(env, args);
|
|
46
41
|
}};
|
|
47
42
|
return std::tuple{callback, data};
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
module;
|
|
2
|
-
#include <string> // IWYU pragma: keep
|
|
3
|
-
#include <type_traits>
|
|
4
1
|
export module napi_js:class_template_storage;
|
|
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
|
|
|
@@ -32,8 +30,8 @@ export template <const auto& Strings>
|
|
|
32
30
|
class class_template_references {
|
|
33
31
|
public:
|
|
34
32
|
template <class Type>
|
|
35
|
-
auto class_template(this auto& self, std::type_identity<Type> /*type*/, const auto& class_template) ->
|
|
36
|
-
constexpr auto name_sv = util::
|
|
33
|
+
auto class_template(this auto& self, std::type_identity<Type> /*type*/, const auto& class_template) -> value_of<class_tag_of<Type>> {
|
|
34
|
+
constexpr auto name_sv = util::make_consteval_string_view(class_template.constructor.name);
|
|
37
35
|
constexpr auto index = class_template_references_of<Strings>.lookup(name_sv);
|
|
38
36
|
if constexpr (!index) {
|
|
39
37
|
// nb: This fails while linking against STL for some reason. So the `constexpr` if works
|
|
@@ -45,7 +43,7 @@ class class_template_references {
|
|
|
45
43
|
static_assert(index, "Class template '"s + name_sv + "' is missing in storage"s);
|
|
46
44
|
}
|
|
47
45
|
auto& reference = self.class_template_references_.at(index).second;
|
|
48
|
-
using value_type = js::napi::
|
|
46
|
+
using value_type = js::napi::value_of<class_tag_of<Type>>;
|
|
49
47
|
if (reference) {
|
|
50
48
|
return value_type::from(reference.get(self));
|
|
51
49
|
} else {
|
package/support/container.cc
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
module;
|
|
2
|
-
#include <bit>
|
|
3
|
-
#include <unordered_map>
|
|
4
1
|
export module napi_js:container;
|
|
5
2
|
import :environment;
|
|
6
|
-
import :utility;
|
|
7
3
|
import nodejs;
|
|
4
|
+
import std;
|
|
8
5
|
import util;
|
|
9
6
|
|
|
10
7
|
namespace js::napi {
|
|
@@ -15,6 +12,7 @@ struct virtual_value_map {
|
|
|
15
12
|
public:
|
|
16
13
|
using container_type = std::unordered_map<napi_value, Type>;
|
|
17
14
|
using iterator = container_type::iterator;
|
|
15
|
+
using key_type = container_type::key_type;
|
|
18
16
|
using mapped_type = container_type::mapped_type;
|
|
19
17
|
|
|
20
18
|
virtual auto end() const -> iterator = 0;
|
|
@@ -26,16 +24,16 @@ template <class Map>
|
|
|
26
24
|
struct concrete_value_map final : virtual_value_map<typename Map::mapped_type> {
|
|
27
25
|
public:
|
|
28
26
|
using container_type = Map;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
using iterator = virtual_value_map<typename Map::mapped_type>::iterator;
|
|
32
|
-
using mapped_type = container_type::mapped_type;
|
|
27
|
+
using typename virtual_value_map<typename Map::mapped_type>::mapped_type;
|
|
28
|
+
using typename virtual_value_map<typename Map::mapped_type>::iterator;
|
|
33
29
|
|
|
34
30
|
virtual auto end() const -> iterator {
|
|
35
31
|
return std::bit_cast<iterator>(map_.end());
|
|
36
32
|
}
|
|
37
33
|
|
|
38
34
|
virtual auto find(napi_value key) const -> iterator {
|
|
35
|
+
// nb: The iterator type between `std::unordered_map<int, int, left>` and
|
|
36
|
+
// `std::unordered_map<int, int, right>` are not technically compatible.
|
|
39
37
|
return std::bit_cast<iterator>(map_.find(key));
|
|
40
38
|
}
|
|
41
39
|
|
|
@@ -58,6 +56,7 @@ class value_map {
|
|
|
58
56
|
public:
|
|
59
57
|
using container_type = virtual_value_map<Type>;
|
|
60
58
|
using iterator = container_type::iterator;
|
|
59
|
+
using key_type = container_type::key_type;
|
|
61
60
|
using mapped_type = container_type::mapped_type;
|
|
62
61
|
|
|
63
62
|
explicit value_map(const environment& env) :
|
|
@@ -68,8 +67,8 @@ class value_map {
|
|
|
68
67
|
} {}
|
|
69
68
|
|
|
70
69
|
auto end() const -> iterator { return map_->end(); }
|
|
71
|
-
auto find(
|
|
72
|
-
auto try_emplace(
|
|
70
|
+
auto find(key_type key) const -> iterator { return map_->find(key); }
|
|
71
|
+
auto try_emplace(key_type key, mapped_type value) -> std::pair<iterator, bool> { return map_->try_emplace(key, std::move(value)); }
|
|
73
72
|
|
|
74
73
|
private:
|
|
75
74
|
virtual_map_type map_;
|
package/support/environment.cc
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
module;
|
|
2
|
-
#include <stdexcept>
|
|
3
1
|
module napi_js;
|
|
4
2
|
import :api;
|
|
5
3
|
import :utility;
|
|
@@ -7,27 +5,41 @@ import util;
|
|
|
7
5
|
|
|
8
6
|
namespace js::napi {
|
|
9
7
|
|
|
10
|
-
environment::environment(napi_env env) :
|
|
8
|
+
environment::environment(napi_env env, bool uses_direct_handles) :
|
|
11
9
|
env_{env},
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const auto indirect_equal = indirect_address_equal{};
|
|
15
|
-
auto* array = napi::invoke(napi_create_array_with_length, env, 1);
|
|
16
|
-
napi::invoke0(napi_set_element, env, array, 0, array);
|
|
17
|
-
auto* result = napi::invoke(napi_get_element, env, array, 0);
|
|
18
|
-
if (direct_equal(array, result)) {
|
|
19
|
-
return true;
|
|
20
|
-
} else if (indirect_equal(array, result)) {
|
|
21
|
-
return false;
|
|
22
|
-
} else {
|
|
23
|
-
throw std::runtime_error{"Exotic napi handle behavior detected"};
|
|
24
|
-
}
|
|
25
|
-
}()} {
|
|
10
|
+
address_equal_{uses_direct_handles},
|
|
11
|
+
uses_direct_handles_{uses_direct_handles} {
|
|
26
12
|
scheduler().open(napi::invoke(napi_get_uv_event_loop, env));
|
|
13
|
+
// nb: `uv_async_t` is closed with an async hook, and not as the finalizer of
|
|
14
|
+
// `napi_set_instance_data`. `uv_close` is async and since nothing is keeping this shared library
|
|
15
|
+
// alive, the finalizer code can be unloaded.
|
|
16
|
+
auto finalizer = [](napi_async_cleanup_hook_handle handle, void* data) -> void {
|
|
17
|
+
auto& env = *static_cast<environment*>(data);
|
|
18
|
+
auto finalizer = util::fn<[](napi_async_cleanup_hook_handle handle) -> void {
|
|
19
|
+
napi::invoke0_noexcept(napi_remove_async_cleanup_hook, handle);
|
|
20
|
+
}>;
|
|
21
|
+
env.scheduler().close(util::function_ref{finalizer, handle});
|
|
22
|
+
};
|
|
23
|
+
napi::invoke0_noexcept(napi_add_async_cleanup_hook, env, finalizer, this, &cleanup_hook_handle_);
|
|
27
24
|
}
|
|
28
25
|
|
|
29
|
-
environment
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
environment::environment(napi_env env) :
|
|
27
|
+
environment{
|
|
28
|
+
env,
|
|
29
|
+
[ & ]() -> bool {
|
|
30
|
+
const auto direct_equal = direct_address_equal{};
|
|
31
|
+
const auto indirect_equal = indirect_address_equal{};
|
|
32
|
+
auto* array = napi::invoke(napi_create_array_with_length, env, 1);
|
|
33
|
+
napi::invoke0(napi_set_element, env, array, 0, array);
|
|
34
|
+
auto* result = napi::invoke(napi_get_element, env, array, 0);
|
|
35
|
+
if (direct_equal(array, result)) {
|
|
36
|
+
return true;
|
|
37
|
+
} else if (indirect_equal(array, result)) {
|
|
38
|
+
return false;
|
|
39
|
+
} else {
|
|
40
|
+
throw std::runtime_error{"Exotic napi handle behavior detected"};
|
|
41
|
+
}
|
|
42
|
+
}()
|
|
43
|
+
} {}
|
|
32
44
|
|
|
33
45
|
} // namespace js::napi
|
package/support/environment.h.cc
CHANGED
|
@@ -1,36 +1,24 @@
|
|
|
1
|
-
module;
|
|
2
|
-
#include <functional>
|
|
3
|
-
#include <memory>
|
|
4
1
|
export module napi_js:environment;
|
|
5
2
|
export import :environment_fwd;
|
|
6
3
|
import :api;
|
|
4
|
+
import :utility;
|
|
5
|
+
import std;
|
|
7
6
|
import util;
|
|
8
7
|
|
|
9
8
|
namespace js::napi {
|
|
10
9
|
|
|
11
|
-
// Internal holder for an environment pointer. Used as a common base class for `visit` & `accept`.
|
|
12
|
-
// This could maybe become something similar to `realm_scope` if the need for it is more common.
|
|
13
|
-
export template <auto_environment Type>
|
|
14
|
-
class environment_scope {
|
|
15
|
-
public:
|
|
16
|
-
explicit environment_scope(Type& env) : env_{env} {}
|
|
17
|
-
|
|
18
|
-
explicit operator napi_env() const { return napi_env{env_.get()}; }
|
|
19
|
-
[[nodiscard]] auto environment() const -> Type& { return env_; }
|
|
20
|
-
|
|
21
|
-
private:
|
|
22
|
-
std::reference_wrapper<Type> env_;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
10
|
// A reference to an environment is used as the lock witness. Generally, you should not have an
|
|
26
11
|
// `environment&` unless you're in the napi thread and locked.
|
|
27
12
|
export class environment : util::non_moveable, public uv_schedulable {
|
|
13
|
+
private:
|
|
14
|
+
environment(napi_env env, bool uses_direct_handles);
|
|
15
|
+
|
|
28
16
|
public:
|
|
29
17
|
explicit environment(napi_env env);
|
|
30
|
-
~environment();
|
|
31
18
|
|
|
32
19
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
|
33
20
|
[[nodiscard]] operator napi_env() const { return env_; }
|
|
21
|
+
[[nodiscard]] auto address_equal() const -> const auto& { return address_equal_; }
|
|
34
22
|
[[nodiscard]] auto uses_direct_handles() const -> bool { return uses_direct_handles_; }
|
|
35
23
|
|
|
36
24
|
template <class Type>
|
|
@@ -50,6 +38,8 @@ export class environment : util::non_moveable, public uv_schedulable {
|
|
|
50
38
|
|
|
51
39
|
private:
|
|
52
40
|
napi_env env_;
|
|
41
|
+
napi_async_cleanup_hook_handle cleanup_hook_handle_{};
|
|
42
|
+
napi::address_equal address_equal_;
|
|
53
43
|
bool uses_direct_handles_;
|
|
54
44
|
};
|
|
55
45
|
|
package/support/error_scope.cc
CHANGED
package/support/initialize.h.cc
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
module;
|
|
2
|
-
#include <cassert>
|
|
3
|
-
#include <tuple>
|
|
4
1
|
export module napi_js:initialize;
|
|
5
|
-
import :environment;
|
|
6
2
|
import :value;
|
|
7
3
|
import nodejs;
|
|
4
|
+
import std;
|
|
8
5
|
import util;
|
|
9
6
|
|
|
10
7
|
namespace js::napi {
|
|
@@ -37,7 +34,7 @@ class napi_js_module final : private detail::initialize_require {
|
|
|
37
34
|
const auto [... indices ] = util::sequence<sizeof...(Args)>;
|
|
38
35
|
auto& client_environment = environment::make_and_set_environment<Environment>(env, std::get<indices>(std::move(args_))...);
|
|
39
36
|
// assign export descriptor to napi-constructor namespace object
|
|
40
|
-
auto exports_local =
|
|
37
|
+
auto exports_local = value_of<dictionary_tag>::from(exports);
|
|
41
38
|
exports_local.assign(client_environment, std::move(make_exports_)(client_environment));
|
|
42
39
|
}
|
|
43
40
|
|
package/support/promise.cc
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
module;
|
|
2
|
-
#include <concepts>
|
|
3
|
-
#include <expected>
|
|
4
|
-
#include <tuple>
|
|
5
|
-
#include <utility>
|
|
6
1
|
export module napi_js:promise;
|
|
7
|
-
import :api;
|
|
8
|
-
import :environment;
|
|
9
2
|
import :value;
|
|
10
|
-
import
|
|
3
|
+
import std;
|
|
11
4
|
|
|
12
5
|
namespace js::napi {
|
|
13
6
|
|
|
14
7
|
// Resolver for `make_promise`
|
|
15
|
-
|
|
8
|
+
template <class Environment, class Dispatch>
|
|
16
9
|
class resolver {
|
|
17
10
|
public:
|
|
18
11
|
resolver(Environment& env, napi_deferred deferred, Dispatch dispatch = {}) :
|
|
@@ -124,7 +117,7 @@ auto make_promise(Environment& env, auto... dispatch) {
|
|
|
124
117
|
auto resolve = resolver{env, deferred, std::move(dispatch)...};
|
|
125
118
|
|
|
126
119
|
// `[ promise, resolver ]`
|
|
127
|
-
return std::tuple{
|
|
120
|
+
return std::tuple{value_of<promise_tag>::from(promise), std::move(resolve)};
|
|
128
121
|
}
|
|
129
122
|
|
|
130
123
|
} // namespace js::napi
|