@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/CMakeLists.txt +13 -2
- package/README.md +8 -8
- package/_module.cc +3 -3
- package/api/finalizer.cc +12 -14
- package/api/napi_scheduler.cc +3 -3
- package/api/napi_scheduler.h.cc +7 -6
- package/api/threadsafe_function.cc +12 -14
- package/api/uv_dlib.cc +4 -3
- package/handle/local.cc +112 -0
- package/handle/reference.cc +5 -5
- package/handle/remote.cc +11 -10
- package/handle/types.cc +9 -132
- package/handle/value.cc +122 -30
- package/package.json +4 -4
- package/support/callback.cc +3 -3
- package/support/callback_storage.cc +2 -2
- package/support/class_template_storage.cc +2 -2
- package/support/host.cc +197 -84
- package/support/host.h.cc +30 -14
- package/support/initialize.h.cc +2 -2
- package/support/promise.cc +10 -8
- package/support/win32_delay_load_hook.cc +12 -0
- package/transfer/accept.cc +34 -34
- package/transfer/accept.h.cc +81 -71
- package/transfer/visit.cc +182 -130
- package/value/array.cc +5 -7
- package/value/array.h.cc +7 -7
- package/value/array_buffer.cc +27 -32
- package/value/array_buffer.h.cc +50 -52
- package/value/class.cc +8 -9
- package/value/class.h.cc +5 -5
- package/value/external.cc +9 -11
- package/value/function.cc +7 -7
- package/value/function.h.cc +2 -2
- package/value/object.cc +5 -8
- package/value/object.h.cc +8 -15
- package/value/primitive.cc +7 -10
- package/value/primitive.h.cc +24 -11
- package/value/record.cc +6 -8
- package/value/record.h.cc +8 -8
- package/value/value.cc +3 -1
- package/handle/bound_value.cc +0 -47
- package/support/host_shim.cc +0 -42
package/CMakeLists.txt
CHANGED
|
@@ -18,7 +18,6 @@ target_sources(${napi_js}
|
|
|
18
18
|
api/uv_dlib.cc
|
|
19
19
|
api/uv_scheduler.cc
|
|
20
20
|
support/environment.cc
|
|
21
|
-
support/host_shim.cc
|
|
22
21
|
support/host.cc
|
|
23
22
|
support/initialize.cc
|
|
24
23
|
transfer/accept.cc
|
|
@@ -39,7 +38,7 @@ target_sources(${napi_js}
|
|
|
39
38
|
api/uv_dlib.h.cc
|
|
40
39
|
api/uv_handle.cc
|
|
41
40
|
api/uv_scheduler.h.cc
|
|
42
|
-
handle/
|
|
41
|
+
handle/local.cc
|
|
43
42
|
handle/reference.cc
|
|
44
43
|
handle/remote.cc
|
|
45
44
|
handle/types.cc
|
|
@@ -69,3 +68,15 @@ target_sources(${napi_js}
|
|
|
69
68
|
value/record.h.cc
|
|
70
69
|
value/value.cc
|
|
71
70
|
)
|
|
71
|
+
|
|
72
|
+
# Enable "delay load" for win32 otherwise the dll will attempt to load node.exe from PATH as a
|
|
73
|
+
# shared library and then start invoking functions from it.
|
|
74
|
+
if(WIN32)
|
|
75
|
+
set(napi_js_delay_load ${napi_js}_delay_load)
|
|
76
|
+
add_library(${napi_js_delay_load} STATIC)
|
|
77
|
+
set_target_properties(${napi_js_delay_load} PROPERTIES CXX_VISIBILITY_PRESET default)
|
|
78
|
+
target_sources(${napi_js_delay_load} PUBLIC support/win32_delay_load_hook.cc)
|
|
79
|
+
target_link_libraries(${napi_js_delay_load} PUBLIC delayimp.lib)
|
|
80
|
+
target_link_libraries(${napi_js} PUBLIC ${napi_js_delay_load})
|
|
81
|
+
target_link_options(${napi_js_delay_load} PUBLIC "-Wl,/DELAYLOAD:node.exe")
|
|
82
|
+
endif()
|
package/README.md
CHANGED
|
@@ -181,20 +181,20 @@ struct enum_values<enum_test> {
|
|
|
181
181
|
|
|
182
182
|
## Variants
|
|
183
183
|
|
|
184
|
-
`std::variant<std::u16string, double>` could be used to accept *either* a
|
|
185
|
-
You can mix and match types as needed.
|
|
184
|
+
`std::variant<std::u16string, std::string, double, std::int32_t>` could be used to accept *either* a
|
|
185
|
+
string or a number value. You can mix and match types as needed. If you use one of the covariant
|
|
186
|
+
types then you must also use its alternative. `std::u16string, std::string`, `double, std::int32_t`,
|
|
187
|
+
and `std::int64_t, js::bigint`.
|
|
186
188
|
|
|
187
189
|
|
|
188
190
|
## Covariants
|
|
189
191
|
|
|
190
192
|
`std::variant<double, int32_t>` can be used to accept *either* a floating point or a signed integer.
|
|
191
193
|
Note that this uses runtime function calls to resolve the covariance. In v8 it will invoke
|
|
192
|
-
`value->IsInt32()` to discover what to return.
|
|
193
|
-
be returned.
|
|
194
|
+
`value->IsInt32()` to discover what to return.
|
|
194
195
|
|
|
195
|
-
`std::variant<std::
|
|
196
|
+
`std::variant<std::u16string, std::string>` can be used in a similar way to accept either a UTF-16
|
|
196
197
|
string or the optimized ASCII string. This uses `value->IsOneByte()` to resolve the covariance.
|
|
197
|
-
Again, in napi a UTF-16 string will always be returned.
|
|
198
198
|
|
|
199
199
|
|
|
200
200
|
## Structures
|
|
@@ -274,8 +274,8 @@ export class database {
|
|
|
274
274
|
using transfer_type = js::tagged_external<database>;
|
|
275
275
|
|
|
276
276
|
auto query(environment& env, std::string query) -> std::string;
|
|
277
|
-
static auto connect(environment& env, std::string uri) -> js::forward<js::napi::
|
|
278
|
-
static auto class_template(environment& env) -> js::napi::
|
|
277
|
+
static auto connect(environment& env, std::string uri) -> js::forward<js::napi::local_of<>>;
|
|
278
|
+
static auto class_template(environment& env) -> js::napi::local_of<class_tag_of<database>> {
|
|
279
279
|
// incomplete
|
|
280
280
|
}
|
|
281
281
|
};
|
package/_module.cc
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
export module napi_js;
|
|
2
2
|
export import :accept;
|
|
3
3
|
export import :api;
|
|
4
|
-
export import :bound_value;
|
|
5
4
|
export import :callback;
|
|
6
5
|
export import :class_definitions;
|
|
7
6
|
export import :class_template_storage;
|
|
8
7
|
export import :environment;
|
|
9
8
|
export import :error_scope;
|
|
10
9
|
export import :function_definitions;
|
|
11
|
-
export import :handle.types;
|
|
12
10
|
export import :initialize;
|
|
13
11
|
export import :promise;
|
|
14
12
|
export import :reference;
|
|
15
13
|
export import :remote;
|
|
16
14
|
export import :string_table;
|
|
17
15
|
export import :utility;
|
|
18
|
-
export import :
|
|
16
|
+
export import :handle.local_of;
|
|
17
|
+
export import :handle.types;
|
|
18
|
+
export import :handle.value_of;
|
|
19
19
|
export import :value;
|
|
20
20
|
export import :visit;
|
package/api/finalizer.cc
CHANGED
|
@@ -7,15 +7,14 @@ namespace js::napi {
|
|
|
7
7
|
|
|
8
8
|
// Generic finalizer for basic `std::unique_ptr<T>`
|
|
9
9
|
template <class Env, class Type, class Deleter>
|
|
10
|
-
auto make_finalizer(std::type_identity<Env> /*type*/, std::unique_ptr<Type, Deleter
|
|
10
|
+
auto make_finalizer(std::type_identity<Env> /*type*/, std::unique_ptr<Type, Deleter> unique) {
|
|
11
11
|
if constexpr (std::is_empty_v<Deleter>) {
|
|
12
12
|
// Finalizer uses a default-constructed deleter
|
|
13
13
|
auto finalize = [](Env /*env*/, void* data, void* /*hint*/) -> void {
|
|
14
14
|
Deleter deleter{};
|
|
15
15
|
deleter(static_cast<Type*>(data));
|
|
16
16
|
};
|
|
17
|
-
|
|
18
|
-
return std::tuple{finalize, nullptr, release};
|
|
17
|
+
return std::tuple{finalize, nullptr, std::move(unique)};
|
|
19
18
|
} else {
|
|
20
19
|
static_assert(std::is_trivially_destructible_v<Deleter>);
|
|
21
20
|
static_assert(sizeof(Deleter) == sizeof(void*));
|
|
@@ -23,28 +22,26 @@ auto make_finalizer(std::type_identity<Env> /*type*/, std::unique_ptr<Type, Dele
|
|
|
23
22
|
auto finalize = [](Env /*env*/, void* data, void* hint) -> void {
|
|
24
23
|
std::bit_cast<Deleter>(hint)(static_cast<Type*>(data));
|
|
25
24
|
};
|
|
26
|
-
|
|
27
|
-
return std::tuple{finalize, std::bit_cast<void*>(unique->get_deleter()), release};
|
|
25
|
+
return std::tuple{finalize, std::bit_cast<void*>(unique.get_deleter()), std::move(unique)};
|
|
28
26
|
}
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
// Generic finalizer for `std::shared_ptr<T>`
|
|
32
30
|
template <class Env, class Type>
|
|
33
|
-
auto make_finalizer(std::type_identity<Env> /*type*/, std::shared_ptr<Type
|
|
31
|
+
auto make_finalizer(std::type_identity<Env> /*type*/, std::shared_ptr<Type> shared) {
|
|
34
32
|
// `shared_ptr<T>*` is passed as the finalizer hint
|
|
35
33
|
using shared_ptr_type = std::shared_ptr<Type>;
|
|
36
|
-
auto* ptr = shared
|
|
37
|
-
auto ptr_ptr = std::make_unique<shared_ptr_type>(std::move(
|
|
34
|
+
auto* ptr = shared.get();
|
|
35
|
+
auto ptr_ptr = std::make_unique<shared_ptr_type>(std::move(shared));
|
|
38
36
|
auto finalize = [](Env /*env*/, void* /*data*/, void* hint) -> void {
|
|
39
37
|
delete static_cast<shared_ptr_type*>(hint);
|
|
40
38
|
};
|
|
41
|
-
|
|
42
|
-
return std::tuple{finalize, ptr_ptr.get(), std::move(release)};
|
|
39
|
+
return std::tuple{finalize, ptr_ptr.get(), std::move(ptr_ptr)};
|
|
43
40
|
}
|
|
44
41
|
|
|
45
42
|
// Apply a finalizer to the given smart pointer type
|
|
46
43
|
template <class Pointer, class Apply>
|
|
47
|
-
auto apply_finalizer(Pointer
|
|
44
|
+
auto apply_finalizer(Pointer smart_ptr, Apply apply) -> decltype(auto) {
|
|
48
45
|
using element_type = Pointer::element_type;
|
|
49
46
|
constexpr auto napi_env_type = []() consteval -> auto {
|
|
50
47
|
if constexpr (std::invocable<Apply, element_type*, node_api_basic_finalize, void*>) {
|
|
@@ -54,11 +51,12 @@ auto apply_finalizer(Pointer unique, Apply apply) -> decltype(auto) {
|
|
|
54
51
|
return type<napi_env>;
|
|
55
52
|
}
|
|
56
53
|
}();
|
|
57
|
-
auto
|
|
54
|
+
auto* pointer = smart_ptr.get();
|
|
55
|
+
auto [ finalize, hint, releasable ] = make_finalizer(napi_env_type, std::move(smart_ptr));
|
|
58
56
|
auto result = util::regular_return{[ & ] -> decltype(auto) {
|
|
59
|
-
return apply(
|
|
57
|
+
return apply(pointer, finalize, hint);
|
|
60
58
|
}}();
|
|
61
|
-
release();
|
|
59
|
+
releasable.release();
|
|
62
60
|
return *std::move(result);
|
|
63
61
|
}
|
|
64
62
|
|
package/api/napi_scheduler.cc
CHANGED
|
@@ -10,11 +10,11 @@ napi_scheduler::napi_scheduler(napi_env env) :
|
|
|
10
10
|
fn_.unref(env);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
napi_scheduler::operator bool() const {
|
|
13
|
+
napi_scheduler::operator bool() const noexcept {
|
|
14
14
|
return bool{fn_};
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
auto napi_scheduler::close(threadsafe_function_type::close_callback close) -> void {
|
|
17
|
+
auto napi_scheduler::close(threadsafe_function_type::close_callback close) noexcept -> void {
|
|
18
18
|
fn_.close(close);
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -32,7 +32,7 @@ auto napi_scheduler::increment_ref(node_api_basic_env env) const -> void {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
auto napi_scheduler::storage::operator()(napi_env env, napi_value value, task_type& task) -> void {
|
|
35
|
+
auto napi_scheduler::storage::operator()(napi_env env, napi_value value, task_type& task) noexcept -> void {
|
|
36
36
|
task(env, value);
|
|
37
37
|
}
|
|
38
38
|
|
package/api/napi_scheduler.h.cc
CHANGED
|
@@ -10,21 +10,22 @@ namespace js::napi {
|
|
|
10
10
|
export class napi_scheduler {
|
|
11
11
|
private:
|
|
12
12
|
struct storage;
|
|
13
|
-
using task_type = util::move_only_function<auto(napi_env, napi_value)->void>;
|
|
13
|
+
using task_type = util::move_only_function<auto(napi_env, napi_value) noexcept -> void>;
|
|
14
14
|
using threadsafe_function_type = threadsafe_function_of<storage, task_type>;
|
|
15
15
|
|
|
16
16
|
public:
|
|
17
|
+
napi_scheduler() = default;
|
|
17
18
|
explicit napi_scheduler(napi_env env);
|
|
18
|
-
auto operator()(auto task, auto&&... args) const -> bool;
|
|
19
|
-
explicit operator bool() const;
|
|
20
|
-
auto close(threadsafe_function_type::close_callback close) -> void;
|
|
19
|
+
auto operator()(auto task, auto&&... args) const noexcept -> bool;
|
|
20
|
+
explicit operator bool() const noexcept;
|
|
21
|
+
auto close(threadsafe_function_type::close_callback close) noexcept -> void;
|
|
21
22
|
auto decrement_ref(node_api_basic_env env) const -> void;
|
|
22
23
|
auto increment_ref(node_api_basic_env env) const -> void;
|
|
23
24
|
|
|
24
25
|
private:
|
|
25
26
|
struct storage {
|
|
26
27
|
storage() = default;
|
|
27
|
-
auto operator()(napi_env env, napi_value value, task_type& task) -> void;
|
|
28
|
+
auto operator()(napi_env env, napi_value value, task_type& task) noexcept -> void;
|
|
28
29
|
int refs{};
|
|
29
30
|
};
|
|
30
31
|
|
|
@@ -43,7 +44,7 @@ export class napi_schedulable {
|
|
|
43
44
|
|
|
44
45
|
// ---
|
|
45
46
|
|
|
46
|
-
auto napi_scheduler::operator()(auto task, auto&&... args) const -> bool {
|
|
47
|
+
auto napi_scheduler::operator()(auto task, auto&&... args) const noexcept -> bool {
|
|
47
48
|
return fn_(
|
|
48
49
|
[ task = std::move(task),
|
|
49
50
|
... args = std::forward<decltype(args)>(args) ](
|
|
@@ -13,6 +13,7 @@ class threadsafe_function_of : util::non_copyable {
|
|
|
13
13
|
public:
|
|
14
14
|
using close_callback = util::function_ref<auto()->void>;
|
|
15
15
|
|
|
16
|
+
threadsafe_function_of() = default;
|
|
16
17
|
explicit threadsafe_function_of(auto& env, napi_value value, auto&&... args);
|
|
17
18
|
threadsafe_function_of(const threadsafe_function_of&);
|
|
18
19
|
threadsafe_function_of(threadsafe_function_of&&) noexcept;
|
|
@@ -20,12 +21,12 @@ class threadsafe_function_of : util::non_copyable {
|
|
|
20
21
|
auto operator=(const threadsafe_function_of&) -> threadsafe_function_of& = delete;
|
|
21
22
|
auto operator=(threadsafe_function_of&&) -> threadsafe_function_of& = delete;
|
|
22
23
|
|
|
23
|
-
auto close(close_callback callback) -> void;
|
|
24
|
+
auto close(close_callback callback) noexcept -> void;
|
|
24
25
|
auto ref(node_api_basic_env env) const -> void;
|
|
25
26
|
auto unref(node_api_basic_env env) const -> void;
|
|
26
|
-
auto operator()(Message message) const -> bool;
|
|
27
|
-
auto operator*() const -> Context& { return get(); }
|
|
28
|
-
explicit operator bool() const { return tsfn_ != nullptr; }
|
|
27
|
+
auto operator()(Message message) const noexcept -> bool;
|
|
28
|
+
auto operator*() const noexcept -> Context& { return get(); }
|
|
29
|
+
explicit operator bool() const noexcept { return tsfn_ != nullptr; }
|
|
29
30
|
|
|
30
31
|
private:
|
|
31
32
|
struct storage : Context {
|
|
@@ -36,11 +37,11 @@ class threadsafe_function_of : util::non_copyable {
|
|
|
36
37
|
private:
|
|
37
38
|
close_callback close_hook_{[] -> void {}};
|
|
38
39
|
};
|
|
39
|
-
auto get() const -> storage&;
|
|
40
|
+
auto get() const noexcept -> storage&;
|
|
40
41
|
|
|
41
42
|
constexpr static auto trivial_message =
|
|
42
43
|
std::is_trivially_destructible_v<Message> && sizeof(Message) <= sizeof(void*);
|
|
43
|
-
mutable napi_threadsafe_function tsfn_;
|
|
44
|
+
mutable napi_threadsafe_function tsfn_{};
|
|
44
45
|
};
|
|
45
46
|
|
|
46
47
|
// ---
|
|
@@ -56,9 +57,7 @@ threadsafe_function_of<Context, Message>::threadsafe_function_of(auto& env, napi
|
|
|
56
57
|
auto& context = *static_cast<storage*>(context_ptr);
|
|
57
58
|
if constexpr (trivial_message) {
|
|
58
59
|
if (env != nullptr) {
|
|
59
|
-
|
|
60
|
-
std::memcpy(&message, &data, sizeof(Message));
|
|
61
|
-
context(env, value, message);
|
|
60
|
+
context(env, value, util::bit_truncation_cast<Message>(data));
|
|
62
61
|
}
|
|
63
62
|
} else {
|
|
64
63
|
auto message = std::unique_ptr<Message>{static_cast<Message*>(data)};
|
|
@@ -98,7 +97,7 @@ threadsafe_function_of<Context, Message>::~threadsafe_function_of() {
|
|
|
98
97
|
}
|
|
99
98
|
|
|
100
99
|
template <class Context, class Message>
|
|
101
|
-
auto threadsafe_function_of<Context, Message>::close(close_callback callback) -> void {
|
|
100
|
+
auto threadsafe_function_of<Context, Message>::close(close_callback callback) noexcept -> void {
|
|
102
101
|
get().close_hook_ = callback;
|
|
103
102
|
napi::invoke0_noexcept(napi_release_threadsafe_function, std::exchange(tsfn_, nullptr), napi_tsfn_abort);
|
|
104
103
|
}
|
|
@@ -114,7 +113,7 @@ auto threadsafe_function_of<Context, Message>::unref(node_api_basic_env env) con
|
|
|
114
113
|
}
|
|
115
114
|
|
|
116
115
|
template <class Context, class Message>
|
|
117
|
-
auto threadsafe_function_of<Context, Message>::operator()(Message message) const -> bool {
|
|
116
|
+
auto threadsafe_function_of<Context, Message>::operator()(Message message) const noexcept -> bool {
|
|
118
117
|
auto check = [ & ](napi_status status) {
|
|
119
118
|
switch (status) {
|
|
120
119
|
case napi_ok:
|
|
@@ -133,8 +132,7 @@ auto threadsafe_function_of<Context, Message>::operator()(Message message) const
|
|
|
133
132
|
}
|
|
134
133
|
};
|
|
135
134
|
if constexpr (trivial_message) {
|
|
136
|
-
|
|
137
|
-
std::memcpy(&data, &message, sizeof(Message));
|
|
135
|
+
auto* data = util::bit_padding_cast<void*>(message);
|
|
138
136
|
return check(napi_call_threadsafe_function(tsfn_, data, napi_tsfn_nonblocking));
|
|
139
137
|
} else {
|
|
140
138
|
auto message_ptr = std::make_unique<Message>(std::move(message));
|
|
@@ -147,7 +145,7 @@ auto threadsafe_function_of<Context, Message>::operator()(Message message) const
|
|
|
147
145
|
}
|
|
148
146
|
|
|
149
147
|
template <class Context, class Message>
|
|
150
|
-
auto threadsafe_function_of<Context, Message>::get() const -> storage& {
|
|
148
|
+
auto threadsafe_function_of<Context, Message>::get() const noexcept -> storage& {
|
|
151
149
|
auto* context = napi::invoke_noexcept(napi_get_threadsafe_function_context, tsfn_);
|
|
152
150
|
return *reinterpret_cast<storage*>(context);
|
|
153
151
|
}
|
package/api/uv_dlib.cc
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
module napi_js;
|
|
2
2
|
import :api.uv_dlib;
|
|
3
|
+
import :support.host;
|
|
3
4
|
import util;
|
|
4
5
|
|
|
5
6
|
namespace js::napi {
|
|
6
7
|
|
|
7
8
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
|
8
9
|
uv_dlib::uv_dlib(const std::string& filename) {
|
|
9
|
-
if (
|
|
10
|
-
throw js::runtime_error{util::transcode_string<char16_t>(std::string_view{
|
|
10
|
+
if (host_uv_dlopen(filename.c_str(), &lib_) != 0) {
|
|
11
|
+
throw js::runtime_error{util::transcode_string<char16_t>(std::string_view{host_uv_dlerror(&lib_)})};
|
|
11
12
|
}
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -20,7 +21,7 @@ auto uv_dlib::operator=(uv_dlib&& right) noexcept -> uv_dlib& {
|
|
|
20
21
|
|
|
21
22
|
uv_dlib::~uv_dlib() {
|
|
22
23
|
if (lib_.handle != nullptr) {
|
|
23
|
-
|
|
24
|
+
host_uv_dlclose(&lib_);
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
|
package/handle/local.cc
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
export module napi_js:handle.local_of;
|
|
2
|
+
import :handle.types;
|
|
3
|
+
import auto_js;
|
|
4
|
+
import nodejs;
|
|
5
|
+
import std;
|
|
6
|
+
import util;
|
|
7
|
+
|
|
8
|
+
namespace js::napi {
|
|
9
|
+
|
|
10
|
+
// Map of `local_of<Tag>` to its concrete implementation class
|
|
11
|
+
template <class Tag>
|
|
12
|
+
struct local_specialization;
|
|
13
|
+
|
|
14
|
+
// Tagged napi_value. Each `local_of<T>` inherits from the tag before it which makes overloading
|
|
15
|
+
// acceptor functions naturally hierarchical.
|
|
16
|
+
export template <class Tag = value_tag>
|
|
17
|
+
class local_of : public local_of<typename Tag::tag_type> {
|
|
18
|
+
protected:
|
|
19
|
+
using local_type = local_specialization<Tag>::type;
|
|
20
|
+
explicit local_of(napi_value value) : local_of<typename Tag::tag_type>{value} {}
|
|
21
|
+
|
|
22
|
+
public:
|
|
23
|
+
local_of() = default;
|
|
24
|
+
using tag_type = Tag;
|
|
25
|
+
|
|
26
|
+
// Constructor from tagged `runtime_handle` flavors
|
|
27
|
+
explicit local_of(local_type value)
|
|
28
|
+
requires(type<local_type> != type<runtime_handle>) :
|
|
29
|
+
local_of{napi_value{value}} {}
|
|
30
|
+
|
|
31
|
+
// "Downcast" to a more specific tag. Potentially unsafe.
|
|
32
|
+
template <std::convertible_to<Tag> To>
|
|
33
|
+
auto cast(To /*tag*/) const -> local_of<To> { return local_of<To>::from(*this); }
|
|
34
|
+
|
|
35
|
+
// Construct from any `napi_value`. Potentially unsafe.
|
|
36
|
+
static auto from(napi_value value_) -> local_of<Tag> { return std::bit_cast<local_of<Tag>>(value_); }
|
|
37
|
+
|
|
38
|
+
// Forward `make` to specialization
|
|
39
|
+
static auto make(auto&&... args) -> local_of<Tag> { return local_type::make(std::forward<decltype(args)>(args)...); }
|
|
40
|
+
|
|
41
|
+
// Dereference operators
|
|
42
|
+
auto operator*() const -> local_type { return std::bit_cast<local_type>(napi_value{*this}); }
|
|
43
|
+
auto operator->() const -> auto { return util::pointer_delegate{**this}; }
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Sentinel instantiation
|
|
47
|
+
template <>
|
|
48
|
+
class local_of<void> : public runtime_handle {
|
|
49
|
+
public:
|
|
50
|
+
using runtime_handle::runtime_handle;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Deduction guide
|
|
54
|
+
template <class Type>
|
|
55
|
+
local_of(Type value) -> local_of<typename Type::tag_type>;
|
|
56
|
+
|
|
57
|
+
// Details applied to each level of the `local_of<T>` hierarchy.
|
|
58
|
+
template <class Tag>
|
|
59
|
+
struct local_next : local_specialization<typename Tag::tag_type>::type {
|
|
60
|
+
using local_specialization<typename Tag::tag_type>::type::type;
|
|
61
|
+
using tag_type = Tag;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// `local_of<Tag>` implementation specializations. The default specialization selects the nearest
|
|
65
|
+
// specialization, or simply `runtime_handle` as the base class.
|
|
66
|
+
template <class Type> class local_for_class_of;
|
|
67
|
+
template <class Type> class local_for_typed_array_of;
|
|
68
|
+
|
|
69
|
+
template <class Tag>
|
|
70
|
+
struct local_specialization
|
|
71
|
+
: local_specialization<typename Tag::tag_type> {};
|
|
72
|
+
|
|
73
|
+
template <>
|
|
74
|
+
struct local_specialization<void>
|
|
75
|
+
: std::type_identity<runtime_handle> {};
|
|
76
|
+
|
|
77
|
+
template <>
|
|
78
|
+
struct local_specialization<object_tag>
|
|
79
|
+
: std::type_identity<class local_for_object> {};
|
|
80
|
+
|
|
81
|
+
template <>
|
|
82
|
+
struct local_specialization<function_tag>
|
|
83
|
+
: std::type_identity<class local_for_function> {};
|
|
84
|
+
|
|
85
|
+
template <>
|
|
86
|
+
struct local_specialization<typed_array_tag>
|
|
87
|
+
: std::type_identity<class local_for_typed_array> {};
|
|
88
|
+
|
|
89
|
+
template <class Type>
|
|
90
|
+
struct local_specialization<typed_array_tag_of<Type>>
|
|
91
|
+
: std::type_identity<class local_for_typed_array_of<Type>> {};
|
|
92
|
+
|
|
93
|
+
template <>
|
|
94
|
+
struct local_specialization<data_view_tag>
|
|
95
|
+
: std::type_identity<class local_for_data_view> {};
|
|
96
|
+
|
|
97
|
+
template <class Type>
|
|
98
|
+
struct local_specialization<class_tag_of<Type>>
|
|
99
|
+
: std::type_identity<class local_for_class_of<Type>> {};
|
|
100
|
+
|
|
101
|
+
template <>
|
|
102
|
+
struct local_specialization<external_tag>
|
|
103
|
+
: std::type_identity<class local_for_external> {};
|
|
104
|
+
|
|
105
|
+
} // namespace js::napi
|
|
106
|
+
|
|
107
|
+
// Specialize for `js::forward`. Makes `js::forward{local_of<Tag>}` infer
|
|
108
|
+
// `js::forward<Tag, ...>`.
|
|
109
|
+
namespace js {
|
|
110
|
+
template <class Tag>
|
|
111
|
+
struct forward_tag_for<napi::local_of<Tag>> : std::type_identity<Tag> {};
|
|
112
|
+
} // namespace js
|
package/handle/reference.cc
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export module napi_js:reference;
|
|
2
2
|
import :api;
|
|
3
|
-
import :
|
|
3
|
+
import :handle.local_of;
|
|
4
4
|
import std;
|
|
5
5
|
import util;
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ class reference_handle : util::non_copyable {
|
|
|
14
14
|
env_{env},
|
|
15
15
|
ref_{napi::invoke(napi_create_reference, env, value, 1)} {}
|
|
16
16
|
|
|
17
|
-
[[nodiscard]] auto env() const ->
|
|
17
|
+
[[nodiscard]] auto env() const -> node_api_basic_env {
|
|
18
18
|
return env_;
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -64,7 +64,7 @@ class reference_handle : util::non_copyable {
|
|
|
64
64
|
explicit operator bool() const { return ref_ != nullptr; }
|
|
65
65
|
|
|
66
66
|
private:
|
|
67
|
-
|
|
67
|
+
node_api_basic_env env_{};
|
|
68
68
|
napi_ref ref_{};
|
|
69
69
|
};
|
|
70
70
|
|
|
@@ -72,7 +72,7 @@ class reference_handle : util::non_copyable {
|
|
|
72
72
|
export template <class Tag>
|
|
73
73
|
class reference : public reference<typename Tag::tag_type> {
|
|
74
74
|
public:
|
|
75
|
-
using value_type =
|
|
75
|
+
using value_type = local_of<Tag>;
|
|
76
76
|
using reference<typename Tag::tag_type>::reference;
|
|
77
77
|
|
|
78
78
|
reference() = default;
|
|
@@ -86,7 +86,7 @@ class reference : public reference<typename Tag::tag_type> {
|
|
|
86
86
|
};
|
|
87
87
|
|
|
88
88
|
template <class Tag>
|
|
89
|
-
reference(auto,
|
|
89
|
+
reference(auto, local_of<Tag>) -> reference<Tag>;
|
|
90
90
|
|
|
91
91
|
// nb: Protected inheritance so that `remote<T> is not comparable to `reference<T>`.
|
|
92
92
|
template <>
|
package/handle/remote.cc
CHANGED
|
@@ -23,14 +23,15 @@ class remote : protected reference_handle {
|
|
|
23
23
|
public:
|
|
24
24
|
using unique_remote = std::unique_ptr<remote, util::function_constant<expire>>;
|
|
25
25
|
|
|
26
|
-
remote(
|
|
26
|
+
remote() = default;
|
|
27
|
+
remote(private_constructor /*private*/, const environment& env, local_of<Tag> value, napi_scheduler scheduler) :
|
|
27
28
|
reference_handle{napi_env{env}, napi_value{value}},
|
|
28
29
|
scheduler_{std::move(scheduler)} {}
|
|
29
30
|
|
|
30
|
-
auto deref(const environment& env) const ->
|
|
31
|
+
auto deref(const environment& env) const -> local_of<Tag>;
|
|
31
32
|
|
|
32
|
-
static auto make_shared(remote_handle_environment auto& env,
|
|
33
|
-
static auto make_unique(remote_handle_environment auto& env,
|
|
33
|
+
static auto make_shared(remote_handle_environment auto& env, local_of<Tag> value) -> std::shared_ptr<remote>;
|
|
34
|
+
static auto make_unique(remote_handle_environment auto& env, local_of<Tag> value) -> unique_remote;
|
|
34
35
|
|
|
35
36
|
private:
|
|
36
37
|
napi_scheduler scheduler_;
|
|
@@ -44,12 +45,12 @@ export template <class Type>
|
|
|
44
45
|
using unique_remote = remote<Type>::unique_remote;
|
|
45
46
|
|
|
46
47
|
export template <class Tag>
|
|
47
|
-
auto make_shared_remote(remote_handle_environment auto& env,
|
|
48
|
+
auto make_shared_remote(remote_handle_environment auto& env, local_of<Tag> value) -> shared_remote<Tag> {
|
|
48
49
|
return remote<Tag>::make_shared(env, value);
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
export template <class Tag>
|
|
52
|
-
auto make_unique_remote(remote_handle_environment auto& env,
|
|
53
|
+
auto make_unique_remote(remote_handle_environment auto& env, local_of<Tag> value) -> unique_remote<Tag> {
|
|
53
54
|
return remote<Tag>::make_unique(env, value);
|
|
54
55
|
}
|
|
55
56
|
|
|
@@ -67,17 +68,17 @@ auto remote<Tag>::expire(remote* ptr) -> void {
|
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
template <class Tag>
|
|
70
|
-
auto remote<Tag>::deref(const environment& env) const ->
|
|
71
|
-
return
|
|
71
|
+
auto remote<Tag>::deref(const environment& env) const -> local_of<Tag> {
|
|
72
|
+
return local_of<Tag>::from(get_value(napi_env{env}));
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
template <class Tag>
|
|
75
|
-
auto remote<Tag>::make_shared(remote_handle_environment auto& env,
|
|
76
|
+
auto remote<Tag>::make_shared(remote_handle_environment auto& env, local_of<Tag> value) -> std::shared_ptr<remote> {
|
|
76
77
|
return std::shared_ptr<remote>{new remote{private_constructor{}, env, value, env.scheduler()}, expire};
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
template <class Tag>
|
|
80
|
-
auto remote<Tag>::make_unique(remote_handle_environment auto& env,
|
|
81
|
+
auto remote<Tag>::make_unique(remote_handle_environment auto& env, local_of<Tag> value) -> unique_remote {
|
|
81
82
|
return unique_remote{new remote{private_constructor{}, env, value, env.scheduler()}};
|
|
82
83
|
}
|
|
83
84
|
|