@auto_js/napi 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/transfer/visit.cc CHANGED
@@ -1,5 +1,5 @@
1
1
  export module napi_js:visit;
2
- import :container;
2
+ import :utility;
3
3
  import :value;
4
4
  import std;
5
5
  import util;
@@ -10,7 +10,7 @@ namespace js::napi {
10
10
  // Instantiated in the acceptor that corresponds to a napi visitor
11
11
  struct reference_map_type {
12
12
  template <class Type>
13
- using type = napi::value_map<Type>;
13
+ using type = napi::unordered_value_map<Type>;
14
14
  };
15
15
 
16
16
  // Visitor which may visit only property names. `symbol` should probably be rethought since they are
@@ -104,7 +104,6 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
104
104
  using reference_map_t<Reference, reference_map_type>::lookup_or_visit;
105
105
 
106
106
  visit_value(auto* /*transfer*/, Environment& env) :
107
- reference_map_t<Reference, reference_map_type>{env},
108
107
  env_{env} {}
109
108
 
110
109
  // If the private `immediate` operation is defined: this public operation will first
@@ -135,7 +134,7 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
135
134
 
136
135
  template <class Accept>
137
136
  auto operator()(value_of<number_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
138
- if (std::bit_cast<v8::Local<v8::Number>>(subject)->IsInt32()) {
137
+ if (maybe_fast_is_number_int32(subject).value_or(false)) {
139
138
  return immediate(value_of<number_tag_of<std::int32_t>>::from(subject), accept);
140
139
  } else {
141
140
  return immediate(value_of<number_tag_of<double>>::from(subject), accept);
@@ -153,81 +152,87 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
153
152
 
154
153
  // Check the reference map, and lookup type via napi
155
154
  return lookup_or_visit(subject, [ & ]() -> accept_target_t<Accept> {
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);
226
- }
227
- std::unreachable();
228
- },
155
+ // This is the pure-napi implementation
156
+ auto slow_path = [ & ]() -> accept_target_t<Accept> {
157
+ auto type_of = napi::invoke(napi_typeof, napi_env{*this}, subject);
158
+ switch (type_of) {
159
+ case napi_undefined:
160
+ return (*this)(value_of<undefined_tag>::from(subject), accept);
161
+ case napi_null:
162
+ return (*this)(value_of<null_tag>::from(subject), accept);
163
+ case napi_boolean:
164
+ return (*this)(value_of<boolean_tag>::from(subject), accept);
165
+ case napi_number:
166
+ return (*this)(value_of<number_tag>::from(subject), accept);
167
+ case napi_string:
168
+ return immediate(value_of<string_tag>::from(subject), accept);
169
+ case napi_symbol:
170
+ return immediate(value_of<symbol_tag>::from(subject), accept);
171
+ case napi_object:
172
+ return immediate(value_of<object_tag>::from(subject), accept);
173
+ case napi_function:
174
+ return immediate(value_of<function_tag>::from(subject), accept);
175
+ case napi_external:
176
+ return immediate(value_of<external_tag>::from(subject), accept);
177
+ case napi_bigint:
178
+ return immediate(value_of<bigint_tag>::from(subject), accept);
229
179
  }
230
- );
180
+ std::unreachable();
181
+ };
182
+
183
+ if (has_fast_is_functions) {
184
+ return util::template_traverse(
185
+ accept_tags_of_v<Accept>,
186
+ util::overloaded{
187
+ // Fast paths
188
+ [ & ](undefined_tag /*tag*/, auto next) -> accept_target_t<Accept> {
189
+ return fast_is_undefined(subject) ? (*this)(value_of<undefined_tag>::from(subject), accept) : next();
190
+ },
191
+ [ & ](null_tag /*tag*/, auto next) -> accept_target_t<Accept> {
192
+ return fast_is_null(subject) ? (*this)(value_of<null_tag>::from(subject), accept) : next();
193
+ },
194
+ [ & ](boolean_tag /*tag*/, auto next) -> accept_target_t<Accept> {
195
+ return fast_is_boolean(subject) ? (*this)(value_of<boolean_tag>::from(subject), accept) : next();
196
+ },
197
+ [ & ](number_tag /*tag*/, auto next) -> accept_target_t<Accept> {
198
+ return fast_is_number(subject) ? (*this)(value_of<number_tag>::from(subject), accept) : next();
199
+ },
200
+ [ & ](string_tag /*tag*/, auto next) -> accept_target_t<Accept> {
201
+ return fast_is_string(subject) ? immediate(value_of<string_tag>::from(subject), accept) : next();
202
+ },
203
+ [ & ](bigint_tag /*tag*/, auto next) -> accept_target_t<Accept> {
204
+ return fast_is_bigint(subject) ? immediate(value_of<bigint_tag>::from(subject), accept) : next();
205
+ },
206
+ [ & ](date_tag /*tag*/, auto next) -> accept_target_t<Accept> {
207
+ return napi::invoke(napi_is_date, napi_env{*this}, subject) ? immediate(value_of<date_tag>::from(subject), accept) : next();
208
+ },
209
+ [ & ](list_tag /*tag*/, auto next) -> accept_target_t<Accept> {
210
+ return fast_is_array(subject) ? immediate(value_of<list_tag>::from(subject), accept) : next();
211
+ },
212
+ [ & ](object_tag /*tag*/, auto next) -> accept_target_t<Accept> {
213
+ // nb: You can't really skip the subsequent is promise, is date, is arraybuffer, etc
214
+ // checks. We don't really want to accept those types here, I don't think..
215
+ return fast_is_object(subject) ? immediate(value_of<object_tag>::from(subject), accept) : next();
216
+ },
217
+ [ & ](function_tag /*tag*/, auto next) -> accept_target_t<Accept> {
218
+ return fast_is_function(subject) ? immediate(value_of<function_tag>::from(subject), accept) : next();
219
+ },
220
+
221
+ // Skip these, otherwise `number_tag` and `string_tag` are invoked twice, which we don't
222
+ // differentiate between.
223
+ []<class Type>(number_tag_of<Type> /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
224
+ []<class Type>(string_tag_of<Type> /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
225
+
226
+ // Unknown tag
227
+ [](auto /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
228
+
229
+ // Slow path
230
+ slow_path,
231
+ }
232
+ );
233
+ } else {
234
+ return slow_path();
235
+ }
231
236
  });
232
237
  }
233
238
 
@@ -267,10 +272,10 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
267
272
  // strings
268
273
  template <class Accept>
269
274
  auto immediate(value_of<string_tag> subject, const Accept& accept) -> accept_target_t<Accept> {
270
- if (std::bit_cast<v8::Local<v8::String>>(subject)->IsOneByte()) {
271
- return accept_tagged(value_of<string_tag_of<char16_t>>::from(subject), accept);
272
- } else {
275
+ if (maybe_fast_is_string_one_byte(subject).value_or(false)) {
273
276
  return accept_tagged(value_of<string_tag_of<char>>::from(subject), accept);
277
+ } else {
278
+ return accept_tagged(value_of<string_tag_of<char16_t>>::from(subject), accept);
274
279
  }
275
280
  }
276
281
 
@@ -291,7 +296,7 @@ struct visit_value : reference_map_t<Reference, reference_map_type> {
291
296
  return immediate(value_of<typed_array_tag>::from(subject), accept);
292
297
  } else if (napi::invoke(napi_is_dataview, napi_env{*this}, subject)) {
293
298
  return immediate(value_of<data_view_tag>::from(subject), accept);
294
- } else if (std::bit_cast<v8::Local<v8::Object>>(subject)->IsSharedArrayBuffer()) {
299
+ } else if (maybe_is_shared_array_buffer(env_.get(), subject).value_or(false)) {
295
300
  return immediate(value_of<shared_array_buffer_tag>::from(subject), accept);
296
301
  } else if (napi::invoke(napi_is_arraybuffer, napi_env{*this}, subject)) {
297
302
  return immediate(value_of<array_buffer_tag>::from(subject), accept);
@@ -1,6 +1,7 @@
1
1
  module napi_js;
2
2
  import :api;
3
3
  import :array_buffer;
4
+ import :support.host;
4
5
  import std;
5
6
  import v8;
6
7
 
@@ -8,18 +9,6 @@ namespace js::napi {
8
9
 
9
10
  // `bound_value_for_data_block`
10
11
  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
-
17
- // `bound_value_for_array_buffer`
18
- bound_value_for_array_buffer::operator js::array_buffer() const {
19
- return js::array_buffer{std::span<std::byte>{*this}};
20
- }
21
-
22
- bound_value_for_array_buffer::operator std::span<std::byte>() const {
23
12
  // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
24
13
  void* bytes;
25
14
  // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
@@ -28,6 +17,11 @@ bound_value_for_array_buffer::operator std::span<std::byte>() const {
28
17
  return std::span{reinterpret_cast<std::byte*>(bytes), byte_length};
29
18
  }
30
19
 
20
+ // `bound_value_for_array_buffer`
21
+ bound_value_for_array_buffer::operator js::array_buffer() const {
22
+ return js::array_buffer{std::span<std::byte>{*this}};
23
+ }
24
+
31
25
  // `bound_value_for_shared_array_buffer`
32
26
  bound_value_for_shared_array_buffer::operator js::shared_array_buffer() const {
33
27
  auto local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{*this});
@@ -37,11 +31,6 @@ bound_value_for_shared_array_buffer::operator js::shared_array_buffer() const {
37
31
  return js::shared_array_buffer{local->ByteLength(), std::move(data_shared_ptr)};
38
32
  }
39
33
 
40
- bound_value_for_shared_array_buffer::operator std::span<std::byte>() const {
41
- auto local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{*this});
42
- return std::span{reinterpret_cast<std::byte*>(local->Data()), local->ByteLength()};
43
- }
44
-
45
34
  // `value_for_typed_array`
46
35
  auto value_for_typed_array::make(const environment& env, napi_typedarray_type type_tag, value_of<array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> value_of<typed_array_tag> {
47
36
  return value_of<typed_array_tag>::from(napi::invoke(napi_create_typedarray, napi_env{env}, type_tag, length, napi_value{buffer}, byte_offset));
@@ -92,9 +81,7 @@ auto value_for_data_view::make(const environment& env, value_of<array_buffer_tag
92
81
  }
93
82
 
94
83
  auto value_for_data_view::make(const environment& /*env*/, value_of<shared_array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> value_of<data_view_tag> {
95
- auto buffer_local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{buffer});
96
- auto view_local = v8::DataView::New(buffer_local, byte_offset, length);
97
- return value_of<data_view_tag>::from(std::bit_cast<napi_value>(view_local));
84
+ return make_sab_data_view(buffer, byte_offset, length);
98
85
  }
99
86
 
100
87
  // `bound_value_for_data_view`
@@ -20,20 +20,14 @@ class bound_value_for_data_block : public bound_value_next<data_block_tag> {
20
20
  class bound_value_for_array_buffer : public bound_value_next<array_buffer_tag> {
21
21
  public:
22
22
  using bound_value_next<array_buffer_tag>::bound_value_next;
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(); }
25
23
  explicit operator js::array_buffer() const;
26
- explicit operator std::span<std::byte>() const;
27
24
  };
28
25
 
29
26
  // `SharedArrayBuffer`
30
27
  class bound_value_for_shared_array_buffer : public bound_value_next<shared_array_buffer_tag> {
31
28
  public:
32
29
  using bound_value_next<shared_array_buffer_tag>::bound_value_next;
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(); }
35
30
  explicit operator js::shared_array_buffer() const;
36
- explicit operator std::span<std::byte>() const;
37
31
  };
38
32
 
39
33
  // `ArrayBufferView` (hidden superclass of `TypedArray` and `DataView`)
@@ -120,23 +114,7 @@ class value_for_typed_array_of : public value_next<typed_array_tag_of<Type>> {
120
114
 
121
115
  // napi doesn't provide a way to make a typed array view on a shared array buffer
122
116
  static auto make(const environment& /*env*/, value_of<shared_array_buffer_tag> buffer, std::size_t byte_offset, std::size_t length) -> value_of<typed_array_tag_of<Type>> {
123
- using constructor_type = type_t<util::overloaded{
124
- [](std::type_identity<double>) -> std::type_identity<v8::Float64Array> { return {}; },
125
- [](std::type_identity<float>) -> std::type_identity<v8::Float32Array> { return {}; },
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 {}; },
128
- [](std::type_identity<std::int16_t>) -> std::type_identity<v8::Int16Array> { return {}; },
129
- [](std::type_identity<std::int32_t>) -> std::type_identity<v8::Int32Array> { return {}; },
130
- [](std::type_identity<std::int64_t>) -> std::type_identity<v8::BigInt64Array> { return {}; },
131
- [](std::type_identity<std::int8_t>) -> std::type_identity<v8::Int8Array> { return {}; },
132
- [](std::type_identity<std::uint16_t>) -> std::type_identity<v8::Uint16Array> { return {}; },
133
- [](std::type_identity<std::uint32_t>) -> std::type_identity<v8::Uint32Array> { return {}; },
134
- [](std::type_identity<std::uint64_t>) -> std::type_identity<v8::BigUint64Array> { return {}; },
135
- [](std::type_identity<std::uint8_t>) -> std::type_identity<v8::Uint8Array> { return {}; },
136
- }(type<Type>)>;
137
- auto buffer_local = std::bit_cast<v8::Local<v8::SharedArrayBuffer>>(napi_value{buffer});
138
- auto view_local = constructor_type::New(buffer_local, byte_offset, length);
139
- return value_of<typed_array_tag_of<Type>>::from(std::bit_cast<napi_value>(view_local));
117
+ return make_sab_typed_array_of<Type>(buffer, byte_offset, length);
140
118
  }
141
119
  };
142
120
 
package/value/class.cc CHANGED
@@ -42,7 +42,7 @@ auto value_for_class_of<Type>::transfer_construct(auto& env, auto instance, std:
42
42
  napi::invoke0(napi_type_tag_object, napi_env{env}, this_arg, &type_tag_for<element_type>);
43
43
 
44
44
  // Wrap w/ finalizer
45
- return apply_finalizer(std::move(instance), [ & ](element_type* instance, napi_finalize finalize, void* hint) -> napi_value {
45
+ return apply_finalizer(std::move(instance), [ & ](element_type* instance, node_api_basic_finalize finalize, void* hint) -> napi_value {
46
46
  napi::invoke0(napi_wrap, napi_env{env}, this_arg, instance, finalize, hint, nullptr);
47
47
  return this_arg;
48
48
  });
@@ -1,77 +0,0 @@
1
- export module napi_js:container;
2
- import :environment;
3
- import nodejs;
4
- import std;
5
- import util;
6
-
7
- namespace js::napi {
8
-
9
- // Map container for napi values
10
- template <class Type>
11
- struct virtual_value_map {
12
- public:
13
- using container_type = std::unordered_map<napi_value, Type>;
14
- using iterator = container_type::iterator;
15
- using key_type = container_type::key_type;
16
- using mapped_type = container_type::mapped_type;
17
-
18
- virtual auto end() const -> iterator = 0;
19
- virtual auto find(napi_value key) const -> iterator = 0;
20
- virtual auto try_emplace(napi_value key, Type value) -> std::pair<iterator, bool> = 0;
21
- };
22
-
23
- template <class Map>
24
- struct concrete_value_map final : virtual_value_map<typename Map::mapped_type> {
25
- public:
26
- using container_type = Map;
27
- using typename virtual_value_map<typename Map::mapped_type>::mapped_type;
28
- using typename virtual_value_map<typename Map::mapped_type>::iterator;
29
-
30
- virtual auto end() const -> iterator {
31
- return std::bit_cast<iterator>(map_.end());
32
- }
33
-
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.
37
- return std::bit_cast<iterator>(map_.find(key));
38
- }
39
-
40
- virtual auto try_emplace(napi_value key, mapped_type value) -> std::pair<iterator, bool> {
41
- auto [ it, inserted ] = map_.try_emplace(key, std::move(value));
42
- return std::pair{std::bit_cast<iterator>(it), inserted};
43
- }
44
-
45
- private:
46
- container_type map_;
47
- };
48
-
49
- export template <class Type>
50
- class value_map {
51
- private:
52
- using direct_map_type = concrete_value_map<std::unordered_map<napi_value, Type, direct_address_hash, direct_address_equal>>;
53
- using indirect_map_type = concrete_value_map<std::unordered_map<napi_value, Type, indirect_address_hash, indirect_address_equal>>;
54
- using virtual_map_type = util::covariant_value<virtual_value_map<Type>, direct_map_type, indirect_map_type>;
55
-
56
- public:
57
- using container_type = virtual_value_map<Type>;
58
- using iterator = container_type::iterator;
59
- using key_type = container_type::key_type;
60
- using mapped_type = container_type::mapped_type;
61
-
62
- explicit value_map(const environment& env) :
63
- map_{
64
- env.uses_direct_handles()
65
- ? virtual_map_type{direct_map_type{}}
66
- : virtual_map_type{indirect_map_type{}}
67
- } {}
68
-
69
- auto end() const -> iterator { return map_->end(); }
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)); }
72
-
73
- private:
74
- virtual_map_type map_;
75
- };
76
-
77
- } // namespace js::napi