@auto_js/v8 0.0.2 → 0.0.5

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 CHANGED
@@ -49,10 +49,13 @@ target_sources("${TARGET_NAME}"
49
49
  value/array.h.cc
50
50
  value/callback_info.cc
51
51
  value/fixed_array.h.cc
52
+ value/function.cc
53
+ value/function.h.cc
52
54
  value/handle.cc
53
55
  value/object.h.cc
54
56
  value/primitive.h.cc
55
57
  value/tag.cc
58
+ value/value.cc
56
59
  )
57
60
 
58
61
  if(TARGET_NAME STREQUAL "embedded_v8_js")
package/_module.cc CHANGED
@@ -1,21 +1,18 @@
1
1
  export module v8_js;
2
2
  export import :accept;
3
- export import :array_buffer;
4
- export import :array;
5
3
  export import :boost;
6
4
  export import :callback_info;
7
5
  export import :callback;
8
6
  export import :collected_handle;
9
7
  export import :error;
10
- export import :fixed_array;
8
+ export import :function_definitions;
11
9
  export import :handle;
12
10
  export import :handle.value;
13
11
  export import :hash;
14
12
  export import :lock;
15
- export import :object;
16
- export import :primitive;
17
13
  export import :remote;
18
14
  export import :unmaybe;
15
+ export import :value;
19
16
  export import :value.tag;
20
17
  export import :visit;
21
18
  export import :weak_map;
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@auto_js/v8",
3
- "version": "0.0.2",
3
+ "version": "0.0.5",
4
4
  "author": "https://github.com/laverdet/",
5
5
  "homepage": "https://github.com/laverdet/isolated-vm/tree/experimental/packages/auto_js/v8",
6
6
  "license": "ISC",
7
7
  "dependencies": {
8
- "@auto_js/js": "^0.0.2",
9
- "@auto_js/v8_exports": "^0.0.2"
8
+ "@auto_js/js": "^0.0.5",
9
+ "@auto_js/v8_exports": "^0.0.3"
10
10
  },
11
11
  "repository": {
12
12
  "type": "git",
@@ -35,7 +35,7 @@ constexpr auto make_free_function_with_try_catch =
35
35
  callback,
36
36
  std::tuple_cat(
37
37
  std::forward_as_tuple(lock),
38
- js::transfer_out<std::tuple<Args...>>(info, lock)
38
+ js::transfer_out<std::tuple<js::functional::parameter_transfer_as_t<Args>...>>(info, lock)
39
39
  )
40
40
  );
41
41
  }};
@@ -15,9 +15,7 @@ constexpr auto make_plain_callback =
15
15
  ) -> auto {
16
16
  return util::bind{
17
17
  [](auto& function, const v8::FunctionCallbackInfo<v8::Value>& info) -> void {
18
- auto isolate_witness = isolate_lock_witness::make_witness(info.GetIsolate());
19
- auto context_witness = context_lock_witness::from_isolate(isolate_witness);
20
- function(context_witness, info);
18
+ function(context_lock_witness{info}, info);
21
19
  },
22
20
  std::move(function),
23
21
  };
@@ -32,9 +30,8 @@ constexpr auto make_decorated_callback =
32
30
  ) -> auto {
33
31
  return util::bind{
34
32
  [](auto& agent, auto& function, const v8::FunctionCallbackInfo<v8::Value>& info) -> void {
35
- auto isolate_witness = isolate_lock_witness::make_witness(info.GetIsolate());
36
- auto context_witness = context_lock_witness::from_isolate(isolate_witness);
37
- auto decorated_witness = context_lock_witness_of<Agent, Implements...>{context_witness, agent};
33
+ auto witness = context_lock_witness{info};
34
+ auto decorated_witness = context_lock_witness_of<Agent, Implements...>{witness, agent};
38
35
  function(decorated_witness, info);
39
36
  },
40
37
  std::ref(*lock),
package/support/lock.cc CHANGED
@@ -36,10 +36,6 @@ isolate_unlock::isolate_unlock(isolate_lock_witness lock) :
36
36
  unlocker_{lock.isolate()} {}
37
37
 
38
38
  // `context_lock_witness`
39
- auto context_lock_witness::from_isolate(isolate_lock_witness lock) -> context_lock_witness {
40
- return context_lock_witness{lock, lock.isolate()->GetCurrentContext()};
41
- }
42
-
43
39
  auto context_lock_witness::make_witness(isolate_lock_witness lock, v8::Local<v8::Context> context) -> context_lock_witness {
44
40
  return context_lock_witness{lock, context};
45
41
  }
package/support/lock.h.cc CHANGED
@@ -105,8 +105,11 @@ export class context_lock_witness : public isolate_lock_witness {
105
105
  context_{context} {}
106
106
 
107
107
  public:
108
+ explicit context_lock_witness(const v8::FunctionCallbackInfo<v8::Value>& info) :
109
+ isolate_lock_witness{isolate_lock_witness::make_witness(info.GetIsolate())},
110
+ context_{isolate()->GetCurrentContext()} {}
111
+
108
112
  [[nodiscard]] auto context() const -> v8::Local<v8::Context> { return context_; }
109
- [[nodiscard]] static auto from_isolate(isolate_lock_witness lock) -> context_lock_witness;
110
113
  [[nodiscard]] static auto make_witness(isolate_lock_witness lock, v8::Local<v8::Context> context) -> context_lock_witness;
111
114
 
112
115
  private:
@@ -108,14 +108,14 @@ auto accept_v8_value::operator()(error_tag /*tag*/, visit_holder /*visit*/, cons
108
108
  }
109
109
 
110
110
  // function
111
- auto accept_v8_value::operator()(function_prototype_tag /*tag*/, visit_holder /*visit*/, v8::Local<v8::FunctionTemplate> subject) const -> v8::Local<v8::Function> {
112
- return unmaybe(subject->GetFunction(context_));
111
+ auto accept_v8_value::operator()(function_prototype_tag /*tag*/, visit_holder /*visit*/, v8::Local<v8::FunctionTemplate> subject) const -> v8::Local<iv8::Function> {
112
+ return unmaybe(subject->GetFunction(context_).As<iv8::Function>());
113
113
  }
114
114
 
115
115
  // data blocks
116
116
  auto accept_v8_value::operator()(array_buffer_tag /*tag*/, visit_holder /*visit*/, js::array_buffer subject) const
117
117
  -> js::referenceable_value<v8::Local<v8::ArrayBuffer>> {
118
- auto byte_length = subject.size();
118
+ auto byte_length = subject.byte_length();
119
119
  auto backing_store = v8::ArrayBuffer::NewBackingStore(
120
120
  std::move(subject).acquire_ownership().release(),
121
121
  byte_length,
@@ -130,7 +130,7 @@ auto accept_v8_value::operator()(array_buffer_tag /*tag*/, visit_holder /*visit*
130
130
 
131
131
  auto accept_v8_value::operator()(shared_array_buffer_tag /*tag*/, visit_holder /*visit*/, js::shared_array_buffer&& subject) const
132
132
  -> js::referenceable_value<v8::Local<v8::SharedArrayBuffer>> {
133
- auto byte_length = subject.size();
133
+ auto byte_length = subject.byte_length();
134
134
  auto backing_store = [ & ]() -> auto {
135
135
  if (byte_length == 0) {
136
136
  // v8 does not call the deleter if `byte_length` is zero. So the heap-allocated shared_ptr
@@ -1,8 +1,7 @@
1
1
  export module v8_js:accept;
2
- import :array_buffer;
3
2
  import :callback_storage;
4
3
  import :hash;
5
- import :primitive;
4
+ import :value;
6
5
  import auto_js;
7
6
  import std;
8
7
  import util;
@@ -105,6 +104,7 @@ struct accept_v8_primitive {
105
104
  struct accept_v8_value : accept_v8_primitive {
106
105
  public:
107
106
  using accept_type = accept_v8_primitive;
107
+ using accept_target_type = v8::Local<v8::Value>;
108
108
  explicit accept_v8_value(auto* transfer, context_lock_witness lock) :
109
109
  accept_type{transfer, lock},
110
110
  context_{lock.context()} {}
@@ -155,7 +155,7 @@ struct accept_v8_value : accept_v8_primitive {
155
155
  }
156
156
 
157
157
  // function
158
- auto operator()(function_prototype_tag /*tag*/, visit_holder /*visit*/, v8::Local<v8::FunctionTemplate> subject) const -> v8::Local<v8::Function>;
158
+ auto operator()(function_prototype_tag /*tag*/, visit_holder /*visit*/, v8::Local<v8::FunctionTemplate> subject) const -> v8::Local<iv8::Function>;
159
159
 
160
160
  // array
161
161
  auto operator()(this const auto& self, list_tag /*tag*/, auto& visit, auto&& subject)
@@ -177,6 +177,40 @@ struct accept_v8_value : accept_v8_primitive {
177
177
  };
178
178
  }
179
179
 
180
+ // vectors
181
+ auto operator()(this const auto& self, vector_tag /*tag*/, auto& visit, auto&& subject)
182
+ -> js::deferred_receiver<v8::Local<v8::Array>, decltype(self), decltype(visit), decltype(subject)> {
183
+ auto [... size ] = util::maybe_range_size(subject);
184
+ return {
185
+ v8::Array::New(self.isolate(), size...),
186
+ std::forward_as_tuple(self, visit, std::forward<decltype(subject)>(subject)),
187
+ [](v8::Local<v8::Array> array, auto& self, auto& visit, auto /*&&*/ subject) -> void {
188
+ std::uint32_t ii = 0;
189
+ auto&& range = util::into_range(std::forward<decltype(subject)>(subject));
190
+ for (auto&& element : util::forward_range(std::forward<decltype(range)>(range))) {
191
+ auto item = visit(std::forward<decltype(element)>(element), self);
192
+ unmaybe(array->Set(self.context_, ii++, item));
193
+ }
194
+ },
195
+ };
196
+ }
197
+
198
+ template <std::size_t Size>
199
+ auto operator()(this const auto& self, tuple_tag<Size> /*tag*/, auto& visit, auto&& subject)
200
+ -> js::deferred_receiver<v8::Local<v8::Array>, decltype(self), decltype(visit), decltype(subject)> {
201
+ return {
202
+ v8::Array::New(self.isolate(), Size),
203
+ std::forward_as_tuple(self, visit, std::forward<decltype(subject)>(subject)),
204
+ [](v8::Local<v8::Array> array, auto& self, auto& visit, auto /*&&*/ tuple) -> void {
205
+ const auto [... indices ] = util::sequence<Size>;
206
+ (..., [ & ]() -> void {
207
+ auto element = visit(indices, std::forward<decltype(tuple)>(tuple), self);
208
+ unmaybe(array->Set(self.context_, indices, element));
209
+ }());
210
+ }
211
+ };
212
+ }
213
+
180
214
  // object
181
215
  auto operator()(this const auto& self, dictionary_tag /*tag*/, auto& visit, auto&& subject)
182
216
  -> js::deferred_receiver<v8::Local<v8::Object>, decltype(self), decltype(visit), decltype(subject)> {
@@ -236,7 +270,7 @@ struct accept_v8_value : accept_v8_primitive {
236
270
  auto operator()(this const auto& self, struct_tag<Size> /*tag*/, auto& visit, auto&& subject)
237
271
  -> js::deferred_receiver<v8::Local<v8::Object>, decltype(self), decltype(visit), decltype(subject)> {
238
272
  return {
239
- v8::Local<v8::Object>::New(self.isolate()),
273
+ v8::Object::New(self.isolate()),
240
274
  std::forward_as_tuple(self, visit, std::forward<decltype(subject)>(subject)),
241
275
  [](v8::Local<v8::Object> object, auto& self, auto& visit, auto /*&&*/ subject) -> void {
242
276
  self.template accept_entry_pair_struct<Size>(visit, object, std::forward<decltype(subject)>(subject));
@@ -269,10 +303,10 @@ struct accept_v8_value_with<context_lock_witness> : accept_v8_value {
269
303
  using accept_v8_value::witness;
270
304
 
271
305
  // function instantiation
272
- auto operator()(function_prototype_tag /*tag*/, visit_holder /*visit*/, auto subject) const -> v8::Local<v8::Function> {
306
+ auto operator()(function_prototype_tag /*tag*/, visit_holder /*visit*/, auto subject) const -> v8::Local<iv8::Function> {
273
307
  auto [ function, length ] = make_free_function<context_lock_witness>(std::move(subject).callback);
274
308
  auto [ callback, data ] = make_callback_storage(witness(), std::move(function));
275
- return unmaybe(v8::Function::New(witness().context(), callback, data, length, v8::ConstructorBehavior::kThrow));
309
+ return unmaybe(v8::Function::New(witness().context(), callback, data, length, v8::ConstructorBehavior::kThrow).template As<iv8::Function>());
276
310
  }
277
311
  };
278
312
 
@@ -286,7 +320,7 @@ struct accept_v8_value_with : accept_v8_value {
286
320
  using accept_v8_value::operator();
287
321
 
288
322
  // function instantiation
289
- auto operator()(function_prototype_tag /*tag*/, visit_holder /*visit*/, auto subject) const -> v8::Local<v8::Function> {
323
+ auto operator()(function_prototype_tag /*tag*/, visit_holder /*visit*/, auto subject) const -> v8::Local<iv8::Function> {
290
324
  auto [ function, length ] = make_free_function<Lock>(std::move(subject).callback);
291
325
  auto [ callback, data ] = make_callback_storage(lock_.get(), std::move(function));
292
326
  return v8::Function::New(lock_.get().context(), callback, data, length, v8::ConstructorBehavior::kThrow);
@@ -315,6 +349,27 @@ struct accept_v8_template : accept_v8_primitive {
315
349
  std::reference_wrapper<const Lock> lock_;
316
350
  };
317
351
 
352
+ // object key lookup (struct_template, etc)
353
+ template <class Meta, auto Key, class Type>
354
+ struct accept_v8_property_value {
355
+ public:
356
+ explicit constexpr accept_v8_property_value(auto* transfer) :
357
+ first{transfer},
358
+ second{transfer} {}
359
+
360
+ auto operator()(dictionary_tag /*tag*/, auto& visit, const auto& subject) const -> Type {
361
+ if (auto local = first(std::type_identity<void>{}, visit.first); subject.has(local)) {
362
+ return visit.second(subject.get(local), second);
363
+ } else {
364
+ return second(undefined_in_tag{}, visit.second, std::monostate{});
365
+ }
366
+ }
367
+
368
+ private:
369
+ mutable visit_key_literal<Key, v8::Local<v8::Object>> first;
370
+ accept_value<Meta, Type> second;
371
+ };
372
+
318
373
  // `return_into(...)`
319
374
  struct return_into_marker {};
320
375
 
@@ -360,8 +415,9 @@ struct accept_v8_return_into : accept_v8_value_with<Lock> {
360
415
  }
361
416
 
362
417
  auto operator()(auto tag, auto& visit, auto&& subject) const -> return_into_marker
363
- requires std::invocable<const accept_type&, decltype(visit), decltype(tag), decltype(subject)> {
364
- return_value_.Set(util::invoke_as<accept_type>(*this, tag, visit, std::forward<decltype(subject)>(subject)));
418
+ requires std::invocable<const accept_type&, decltype(tag), decltype(visit), decltype(subject)> {
419
+ auto value = util::invoke_as<accept_type>(*this, tag, visit, std::forward<decltype(subject)>(subject));
420
+ return_value_.Set(js::dispatch_referenceable(std::move(value)));
365
421
  return {};
366
422
  }
367
423
 
@@ -403,9 +459,12 @@ struct accept_v8_object_assign {
403
459
 
404
460
  namespace js {
405
461
 
462
+ template <class Type>
463
+ struct accept_property_subject<v8::Local<Type>> : std::type_identity<v8::Local<v8::Object>> {};
464
+
406
465
  // primitives
407
466
  template <class Meta, class Type>
408
- requires std::is_base_of_v<v8::Primitive, Type>
467
+ requires std::is_convertible_v<Type, v8::Primitive>
409
468
  struct accept<Meta, v8::Local<Type>> : iv8::accept_v8_primitive {
410
469
  using accept_v8_primitive::accept_v8_primitive;
411
470
  };
@@ -418,7 +477,7 @@ struct accept<Meta, v8::Local<Type>> : iv8::accept_v8_value_with<typename Meta::
418
477
 
419
478
  // templates
420
479
  template <class Meta, class Type>
421
- requires std::is_base_of_v<v8::Template, Type>
480
+ requires std::is_convertible_v<Type, v8::Template>
422
481
  struct accept<Meta, v8::Local<Type>> : iv8::accept_v8_template<Meta, typename Meta::accept_context_type> {
423
482
  using iv8::accept_v8_template<Meta, typename Meta::accept_context_type>::accept_v8_template;
424
483
  };
@@ -441,7 +500,16 @@ struct accept<Meta, v8::MaybeLocal<Type>> : accept<Meta, v8::Local<Type>> {
441
500
  }
442
501
  };
443
502
 
503
+ // object key lookup (struct_template, etc)
504
+ template <class Meta, auto Key, class Type>
505
+ struct accept_property_value<Meta, Key, Type, v8::Local<v8::Object>> : iv8::accept_v8_property_value<Meta, Key, Type> {
506
+ using iv8::accept_v8_property_value<Meta, Key, Type>::accept_v8_property_value;
507
+ };
508
+
444
509
  // return_into
510
+ template <>
511
+ struct accept_property_subject<iv8::return_into_marker> : accept_property_subject<v8::Local<v8::Value>> {};
512
+
445
513
  template <class Meta>
446
514
  struct accept<Meta, iv8::return_into_marker> : iv8::accept_v8_return_into<typename Meta::accept_context_type> {
447
515
  using iv8::accept_v8_return_into<typename Meta::accept_context_type>::accept_v8_return_into;
package/transfer/visit.cc CHANGED
@@ -3,8 +3,8 @@ import :array_buffer;
3
3
  import :callback_info;
4
4
  import :handle.value;
5
5
  import :hash;
6
- import :object;
7
6
  import :unmaybe;
7
+ import :value;
8
8
  import auto_js;
9
9
  import std;
10
10
  import v8;
@@ -30,14 +30,14 @@ struct visit_property_name {
30
30
  auto value = value_of{witness(), subject.As<tag_to_v8<Tag>>()};
31
31
  return accept(tag, *this, value);
32
32
  };
33
- if (subject->IsNumber()) {
34
- return accept_as(number_tag_of<std::int32_t>{});
35
- } else if (subject->IsString()) {
33
+ if (subject->IsString()) {
36
34
  if (subject.As<v8::String>()->IsOneByte()) {
37
35
  return accept_as(string_tag_of<char>{});
38
36
  } else {
39
37
  return accept_as(string_tag_of<char16_t>{});
40
38
  }
39
+ } else if (subject->IsNumber()) {
40
+ return accept_as(number_tag_of<std::int32_t>{});
41
41
  } else {
42
42
  return accept_as(symbol_tag{});
43
43
  }
@@ -51,6 +51,23 @@ struct visit_property_name {
51
51
  std::reference_wrapper<Visit> visit_;
52
52
  };
53
53
 
54
+ // `visit_key_literal` instantiation for v8
55
+ template <auto Key>
56
+ struct visit_v8_key_literal {
57
+ explicit constexpr visit_v8_key_literal(auto* /*transfer*/) {}
58
+
59
+ auto operator()(const auto& /*anything*/, const auto& accept_or_visit) -> v8::Local<v8::Name> {
60
+ if (local_key_.IsEmpty()) {
61
+ constexpr auto key = util::make_consteval_string_view(Key);
62
+ local_key_ = transfer_in<v8::Local<v8::Name>>(key, accept_or_visit.witness());
63
+ }
64
+ return local_key_;
65
+ }
66
+
67
+ private:
68
+ v8::Local<v8::Name> local_key_;
69
+ };
70
+
54
71
  // Implements `Visit`'s non-caching `immediate()` function as a caching visit operation.
55
72
  template <class Visit>
56
73
  struct visit_cached_immediate : Visit {
@@ -126,14 +143,10 @@ struct visit_flat_value : reference_map_t<Reference, visit_reference_map_type> {
126
143
  // primitives
127
144
  template <class Accept>
128
145
  auto immediate(v8::Local<v8::Primitive> subject, const Accept& accept) -> accept_target_t<Accept> {
129
- if (subject->IsNullOrUndefined()) {
130
- if (subject->IsNull()) {
131
- null_ = subject;
132
- return accept(null_tag{}, *this, subject);
133
- } else {
134
- undefined_ = subject;
135
- return accept(undefined_tag{}, *this, subject);
136
- }
146
+ if (subject->IsUndefined()) {
147
+ return accept(undefined_tag{}, *this, subject);
148
+ } else if (subject->IsNull()) {
149
+ return accept(null_tag{}, *this, subject);
137
150
  } else if (subject->IsNumber()) {
138
151
  return (*this)(subject.As<v8::Number>(), accept);
139
152
  } else if (subject->IsName()) {
@@ -148,7 +161,7 @@ struct visit_flat_value : reference_map_t<Reference, visit_reference_map_type> {
148
161
  }
149
162
 
150
163
  template <class Accept, class Type>
151
- requires std::is_base_of_v<primitive_tag, iv8::v8_to_tag<Type>>
164
+ requires std::is_convertible_v<Type, v8::Primitive>
152
165
  auto immediate(v8::Local<Type> subject, const Accept& accept) -> accept_target_t<Accept> {
153
166
  return accept_tagged(subject, accept);
154
167
  }
@@ -201,7 +214,7 @@ struct visit_flat_value : reference_map_t<Reference, visit_reference_map_type> {
201
214
  }
202
215
 
203
216
  template <class Accept, class Type>
204
- requires std::is_base_of_v<data_block_tag, iv8::v8_to_tag<Type>>
217
+ requires std::is_convertible_v<iv8::v8_to_tag<Type>, data_block_tag>
205
218
  auto immediate(v8::Local<Type> subject, const Accept& accept) -> accept_target_t<Accept> {
206
219
  return accept_tagged(subject, accept);
207
220
  }
@@ -212,15 +225,16 @@ struct visit_flat_value : reference_map_t<Reference, visit_reference_map_type> {
212
225
  return accept_tagged(subject, accept);
213
226
  }
214
227
 
215
- // promise (cannot be accepted)
228
+ // promise (maybe could be forwarded)
216
229
  template <class Accept>
217
230
  auto immediate(v8::Local<v8::Promise> subject, const Accept& accept) -> accept_target_t<Accept> {
218
231
  return accept(promise_tag{}, *this, subject);
219
232
  }
220
233
 
221
- // function (cannot be accepted)
222
- template <class Accept>
223
- auto immediate(v8::Local<v8::Function> subject, const Accept& accept) -> accept_target_t<Accept> {
234
+ // function (can be forwarded)
235
+ template <class Type, class Accept>
236
+ requires std::is_convertible_v<Type, v8::Function>
237
+ auto immediate(v8::Local<Type> subject, const Accept& accept) -> accept_target_t<Accept> {
224
238
  return accept(function_tag{}, *this, subject);
225
239
  }
226
240
 
@@ -230,13 +244,8 @@ struct visit_flat_value : reference_map_t<Reference, visit_reference_map_type> {
230
244
  return accept(iv8::v8_to_tag<Type>{}, *this, value_of{witness(), subject});
231
245
  }
232
246
 
233
- [[nodiscard]] auto is_cached_null(v8::Local<v8::Value> value) const { return value == null_; }
234
- [[nodiscard]] auto is_cached_undefined(v8::Local<v8::Value> value) const { return value == undefined_; }
235
-
236
247
  private:
237
248
  isolate_lock_witness isolate_lock_;
238
- v8::Local<v8::Primitive> null_;
239
- v8::Local<v8::Primitive> undefined_;
240
249
  };
241
250
 
242
251
  // Primary visitor w/ `context_lock_witness`
@@ -251,9 +260,8 @@ struct visit_value : visit_flat_value<Target> {
251
260
  public:
252
261
  friend struct visit_flat_value<Target>;
253
262
  using visit_type = visit_flat_value<Target>;
263
+ using visit_type::accept_tagged;
254
264
  using visit_type::immediate;
255
- using visit_type::is_cached_null;
256
- using visit_type::is_cached_undefined;
257
265
  using visit_type::lookup_or_visit;
258
266
  using visit_type::witness;
259
267
  using visit_type::operator();
@@ -266,27 +274,74 @@ struct visit_value : visit_flat_value<Target> {
266
274
 
267
275
  template <class Accept>
268
276
  auto operator()(v8::Local<v8::Value> subject, const Accept& accept) -> accept_target_t<Accept> {
269
- // Check known address values before the map lookup
270
- if (is_cached_null(subject)) {
271
- return accept(null_tag{}, *this, subject);
272
- } else if (is_cached_undefined(subject)) {
273
- return accept(undefined_tag{}, *this, subject);
274
- }
275
277
 
276
278
  // Check the reference map, and check type
277
279
  return lookup_or_visit(subject, [ & ]() -> accept_target_t<Accept> {
278
- if (subject->IsObject()) {
279
- return immediate(subject.As<v8::Object>(), accept);
280
- } else {
281
- return immediate(subject.As<v8::Primitive>(), accept);
282
- }
280
+ return util::template_traverse(
281
+ accept_tags_of_v<Accept>,
282
+ util::overloaded{
283
+ // Fast paths
284
+ [ & ](undefined_tag /*tag*/, auto next) -> accept_target_t<Accept> {
285
+ return subject->IsUndefined() ? accept(undefined_tag{}, *this, subject.As<iv8::Undefined>()) : next();
286
+ },
287
+ [ & ](null_tag /*tag*/, auto next) -> accept_target_t<Accept> {
288
+ return subject->IsNull() ? accept(null_tag{}, *this, subject.As<iv8::Null>()) : next();
289
+ },
290
+ [ & ](boolean_tag /*tag*/, auto next) -> accept_target_t<Accept> {
291
+ return subject->IsBoolean() ? (*this)(subject.As<v8::Boolean>(), accept) : next();
292
+ },
293
+ [ & ](number_tag /*tag*/, auto next) -> accept_target_t<Accept> {
294
+ return subject->IsNumber() ? (*this)(subject.As<v8::Number>(), accept) : next();
295
+ },
296
+ [ & ](string_tag /*tag*/, auto next) -> accept_target_t<Accept> {
297
+ return subject->IsString() ? immediate(subject.As<v8::String>(), accept) : next();
298
+ },
299
+ [ & ](bigint_tag /*tag*/, auto next) -> accept_target_t<Accept> {
300
+ return subject->IsBigInt() ? immediate(subject.As<v8::BigInt>(), accept) : next();
301
+ },
302
+ [ & ](date_tag /*tag*/, auto next) -> accept_target_t<Accept> {
303
+ return subject->IsDate() ? immediate(subject.As<v8::Date>(), accept) : next();
304
+ },
305
+ [ & ](list_tag /*tag*/, auto next) -> accept_target_t<Accept> {
306
+ return subject->IsArray() ? immediate(subject.As<v8::Array>(), accept) : next();
307
+ },
308
+ [ & ](function_tag /*tag*/, auto next) -> accept_target_t<Accept> {
309
+ return subject->IsFunction() ? immediate(subject.As<iv8::Function>(), accept) : next();
310
+ },
311
+
312
+ // Unknown tag
313
+ [](auto /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
314
+
315
+ // Slow path
316
+ [ & ]() -> accept_target_t<Accept> {
317
+ if (subject->IsObject()) {
318
+ return immediate(subject.As<v8::Object>(), accept);
319
+ } else {
320
+ return immediate(subject.As<v8::Primitive>(), accept);
321
+ }
322
+ },
323
+ }
324
+ );
283
325
  });
284
326
  }
285
327
 
286
328
  template <class Accept>
287
329
  auto operator()(v8::Local<iv8::DataBlock> subject, const Accept& accept) -> accept_target_t<Accept> {
288
330
  return lookup_or_visit(subject, [ & ]() -> accept_target_t<Accept> {
289
- return immediate(subject, accept);
331
+ return util::template_traverse(
332
+ accept_tags_of_v<Accept>,
333
+ util::overloaded{
334
+ // Fast paths
335
+ [ & ](data_block_tag /*tag*/, auto /*next*/) -> accept_target_t<Accept> { return accept_tagged(subject, accept); },
336
+ [ & ](array_buffer_tag /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
337
+ [ & ](shared_array_buffer_tag /*tag*/, auto next) -> accept_target_t<Accept> { return next(); },
338
+
339
+ // Slow path
340
+ [ & ]() -> accept_target_t<Accept> {
341
+ return immediate(subject, accept);
342
+ }
343
+ }
344
+ );
290
345
  });
291
346
  }
292
347
 
@@ -314,7 +369,7 @@ struct visit_value : visit_flat_value<Target> {
314
369
  } else if (subject->IsPromise()) {
315
370
  return immediate(subject.As<v8::Promise>(), accept);
316
371
  } else if (subject->IsFunction()) {
317
- return immediate(subject.As<v8::Function>(), accept);
372
+ return immediate(subject.As<iv8::Function>(), accept);
318
373
  } else {
319
374
  auto visit_entry = visit_entry_pair<visit_property_name<visit_value>, visit_value&>{*this};
320
375
  return accept(dictionary_tag{}, visit_entry, value_of{witness(), subject.As<v8::Object>()});
@@ -341,6 +396,8 @@ struct visit_value : visit_flat_value<Target> {
341
396
  return immediate(subject.As<v8::Uint8Array>(), accept);
342
397
  } else if (subject->IsDataView()) {
343
398
  return immediate(subject.As<v8::DataView>(), accept);
399
+ } else if (subject->IsUint8ClampedArray()) {
400
+ return immediate(subject.As<v8::Uint8ClampedArray>(), accept);
344
401
  } else if (subject->IsInt8Array()) {
345
402
  return immediate(subject.As<v8::Int8Array>(), accept);
346
403
  } else if (subject->IsUint16Array()) {
@@ -351,6 +408,8 @@ struct visit_value : visit_flat_value<Target> {
351
408
  return immediate(subject.As<v8::Uint32Array>(), accept);
352
409
  } else if (subject->IsInt32Array()) {
353
410
  return immediate(subject.As<v8::Int32Array>(), accept);
411
+ } else if (subject->IsFloat16Array()) {
412
+ return immediate(subject.As<v8::Float16Array>(), accept);
354
413
  } else if (subject->IsFloat32Array()) {
355
414
  return immediate(subject.As<v8::Float32Array>(), accept);
356
415
  } else if (subject->IsFloat64Array()) {
@@ -359,15 +418,13 @@ struct visit_value : visit_flat_value<Target> {
359
418
  return immediate(subject.As<v8::BigInt64Array>(), accept);
360
419
  } else if (subject->IsBigUint64Array()) {
361
420
  return immediate(subject.As<v8::BigUint64Array>(), accept);
362
- } else if (subject->IsUint8ClampedArray()) {
363
- return immediate(subject.As<v8::Uint8ClampedArray>(), accept);
364
421
  } else {
365
422
  throw js::type_error{u"Received exotic v8 'ArrayBufferView'"};
366
423
  }
367
424
  }
368
425
 
369
426
  template <class Accept, class Type>
370
- requires std::is_base_of_v<array_buffer_view_tag, v8_to_tag<Type>>
427
+ requires std::is_convertible_v<Type, v8::ArrayBufferView>
371
428
  auto immediate(v8::Local<Type> subject, const Accept& accept) -> accept_target_t<Accept> {
372
429
  return accept(v8_to_tag<Type>{}, *this, value_of{witness(), subject});
373
430
  }
@@ -399,7 +456,7 @@ namespace js {
399
456
 
400
457
  // Name visitor (string + symbol)
401
458
  template <class Meta, class Type>
402
- requires std::is_base_of_v<v8::Primitive, Type>
459
+ requires std::is_convertible_v<Type, v8::Primitive>
403
460
  struct visit<Meta, v8::Local<Type>> : iv8::visit_uncached_flat_value_with<Meta> {
404
461
  using iv8::visit_uncached_flat_value_with<Meta>::visit_uncached_flat_value_with;
405
462
  };
@@ -412,7 +469,7 @@ struct visit<Meta, v8::Local<Type>> : iv8::visit_value_with<Meta> {
412
469
 
413
470
  // Template visitor
414
471
  template <class Meta, class Type>
415
- requires std::is_base_of_v<v8::Template, Type>
472
+ requires std::is_convertible_v<Type, v8::Template>
416
473
  struct visit<Meta, v8::Local<Type>> : iv8::visit_template {
417
474
  using iv8::visit_template::visit_template;
418
475
  };
@@ -434,4 +491,10 @@ struct visit<Meta, v8::FunctionCallbackInfo<v8::Value>> : visit<Meta, v8::Local<
434
491
  }
435
492
  };
436
493
 
494
+ // Object key maker for v8 objects
495
+ template <auto Key>
496
+ struct visit_key_literal<Key, v8::Local<v8::Object>> : iv8::visit_v8_key_literal<Key> {
497
+ using iv8::visit_v8_key_literal<Key>::visit_v8_key_literal;
498
+ };
499
+
437
500
  } // namespace js
@@ -4,15 +4,6 @@ import std;
4
4
 
5
5
  namespace js::iv8 {
6
6
 
7
- // `value_for_array_buffer`
8
- value_for_array_buffer::operator js::array_buffer() const {
9
- return js::array_buffer{std::span<std::byte>{*this}};
10
- }
11
-
12
- value_for_array_buffer::operator std::span<std::byte>() const {
13
- return std::span<std::byte>{reinterpret_cast<std::byte*>((*this)->Data()), (*this)->ByteLength()};
14
- }
15
-
16
7
  // `value_for_shared_array_buffer`
17
8
  value_for_shared_array_buffer::operator js::shared_array_buffer() const {
18
9
  auto backing_store = (*this)->GetBackingStore();
@@ -21,8 +12,4 @@ value_for_shared_array_buffer::operator js::shared_array_buffer() const {
21
12
  return js::shared_array_buffer{(*this)->ByteLength(), std::move(data_shared_ptr)};
22
13
  }
23
14
 
24
- value_for_shared_array_buffer::operator std::span<std::byte>() const {
25
- return std::span<std::byte>{reinterpret_cast<std::byte*>((*this)->Data()), (*this)->ByteLength()};
26
- }
27
-
28
15
  } // namespace js::iv8
@@ -7,22 +7,32 @@ import v8;
7
7
 
8
8
  namespace js::iv8 {
9
9
 
10
+ // nb: This handles `v8::ArrayBuffer` and also `v8::SharedArrayBuffer`. They aren't related by
11
+ // inheritance but v8 seem to allow it, and even encourage it.
12
+ class value_for_data_block : public handle_without_lock<v8::ArrayBuffer> {
13
+ public:
14
+ using handle_without_lock<v8::ArrayBuffer>::handle_without_lock;
15
+ [[nodiscard]] auto byte_length() const -> std::size_t { return (*this)->ByteLength(); }
16
+ [[nodiscard]] auto data() const -> std::byte* { return static_cast<std::byte*>((*this)->Data()); }
17
+ explicit operator std::span<std::byte>() const { return {data(), byte_length()}; }
18
+ };
19
+
10
20
  class value_for_array_buffer : public handle_without_lock<v8::ArrayBuffer> {
11
21
  public:
12
22
  using handle_without_lock<v8::ArrayBuffer>::handle_without_lock;
23
+ [[nodiscard]] auto byte_length() const -> std::size_t { return (*this)->ByteLength(); }
13
24
  [[nodiscard]] auto data() const -> std::byte* { return static_cast<std::byte*>((*this)->Data()); }
14
- [[nodiscard]] auto size() const -> std::size_t { return (*this)->ByteLength(); }
15
- explicit operator js::array_buffer() const;
16
- explicit operator std::span<std::byte>() const;
25
+ explicit operator js::array_buffer() const { return js::array_buffer{std::span<std::byte>{*this}}; }
26
+ explicit operator std::span<std::byte>() const { return {data(), byte_length()}; }
17
27
  };
18
28
 
19
29
  class value_for_shared_array_buffer : public handle_without_lock<v8::SharedArrayBuffer> {
20
30
  public:
21
31
  using handle_without_lock<v8::SharedArrayBuffer>::handle_without_lock;
32
+ [[nodiscard]] auto byte_length() const -> std::size_t { return (*this)->ByteLength(); }
22
33
  [[nodiscard]] auto data() const -> std::byte* { return static_cast<std::byte*>((*this)->Data()); }
23
- [[nodiscard]] auto size() const -> std::size_t { return (*this)->ByteLength(); }
24
34
  explicit operator js::shared_array_buffer() const;
25
- explicit operator std::span<std::byte>() const;
35
+ explicit operator std::span<std::byte>() const { return {data(), byte_length()}; }
26
36
  };
27
37
 
28
38
  template <class Type>
@@ -0,0 +1,41 @@
1
+ export module v8_js:function_definitions;
2
+ import :accept;
3
+ import :function;
4
+ import :unmaybe;
5
+ import auto_js;
6
+ import std;
7
+ import v8;
8
+
9
+ namespace js::iv8 {
10
+
11
+ template <class Result = std::monostate>
12
+ auto Function::apply(context_lock_witness lock, auto&& args) -> Result {
13
+ auto result = [ & ]() {
14
+ using args_type = std::vector<v8::Local<v8::Value>>;
15
+ auto handle_scope = v8::EscapableHandleScope{lock.isolate()};
16
+ auto undefined = js::transfer_in_strict<v8::Local<v8::Value>>(std::monostate{}, lock);
17
+ auto argv = js::transfer_in_strict<args_type>(std::forward<decltype(args)>(args), lock);
18
+ auto result = unmaybe(v8::Function::Call(lock.context(), undefined, argv.size(), argv.data()));
19
+ return handle_scope.Escape(result);
20
+ }();
21
+ return js::transfer_out<Result>(result, lock);
22
+ }
23
+
24
+ template <class Result = std::monostate>
25
+ auto Function::call(context_lock_witness lock, auto&&... args) -> Result {
26
+ auto result = [ & ]() {
27
+ using args_type = std::array<v8::Local<v8::Value>, sizeof...(args) + 1>;
28
+ auto handle_scope = v8::EscapableHandleScope{lock.isolate()};
29
+ auto argv = js::transfer_in_strict<args_type>(
30
+ std::tuple_cat(
31
+ std::tuple{std::monostate{}},
32
+ std::forward_as_tuple(std::forward<decltype(args)>(args)...)
33
+ ),
34
+ lock
35
+ );
36
+ return handle_scope.Escape(unmaybe(v8::Function::Call(lock.context(), argv[ 0 ], argv.size() - 1, argv.data() + 1)));
37
+ }();
38
+ return js::transfer_out<Result>(result, lock);
39
+ }
40
+
41
+ } // namespace js::iv8
@@ -0,0 +1,16 @@
1
+ export module v8_js:function;
2
+ import :lock;
3
+ import v8;
4
+
5
+ namespace js::iv8 {
6
+
7
+ class Function : public v8::Function {
8
+ public:
9
+ template <class Result = std::monostate>
10
+ auto apply(context_lock_witness lock, auto&& args) -> Result;
11
+
12
+ template <class Result = std::monostate>
13
+ auto call(context_lock_witness lock, auto&&... args) -> Result;
14
+ };
15
+
16
+ } // namespace js::iv8
package/value/object.cc CHANGED
@@ -1,13 +1,28 @@
1
1
  module v8_js;
2
- import :array;
3
- import :handle;
4
- import :lock;
5
- import :primitive;
2
+ import :object;
6
3
  import std;
7
4
  import v8;
8
5
 
9
6
  namespace js::iv8 {
10
7
 
8
+ constexpr auto has_property(v8::Local<v8::Context> context, v8::Local<v8::Object> object, v8::Local<v8::Name> key) -> bool {
9
+ return iv8::unmaybe(object->HasRealNamedProperty(context, key));
10
+ }
11
+
12
+ constexpr auto has_property(v8::Local<v8::Context> context, v8::Local<v8::Object> object, v8::Local<v8::Number> key) -> bool {
13
+ return iv8::unmaybe(object->HasRealIndexedProperty(context, key.As<v8::Uint32>()->Value()));
14
+ }
15
+
16
+ constexpr auto has_property(v8::Local<v8::Context> context, v8::Local<v8::Object> object, v8::Local<v8::Primitive> key) -> bool {
17
+ // Weird `if` here since there is a "quick" `IsString()` internally, but not for name, number, or
18
+ // symbol.
19
+ if (key->IsString() || !key->IsNumber()) {
20
+ return has_property(context, object, key.As<v8::Name>());
21
+ } else {
22
+ return has_property(context, object, key.As<v8::Number>());
23
+ }
24
+ }
25
+
11
26
  constexpr auto get_property(v8::Local<v8::Context> context, v8::Local<v8::Object> object, v8::Local<v8::Name> key) -> v8::Local<v8::Value> {
12
27
  // Maybe I'm misunderstanding the "without causing side effects" part of `GetRealNamedProperty`'s
13
28
  // documentation, but it definitely invokes getters.
@@ -42,15 +57,27 @@ auto value_for_object::keys() const -> const value_for_array& {
42
57
  return keys_;
43
58
  }
44
59
 
45
- auto value_for_object::get(v8::Local<v8::Name> key) -> v8::Local<v8::Value> {
60
+ auto value_for_object::has(v8::Local<v8::Name> key) const -> bool {
61
+ return has_property(context(), util::slice(*this), key);
62
+ }
63
+
64
+ auto value_for_object::has(v8::Local<v8::Number> key) const -> bool {
65
+ return has_property(context(), util::slice(*this), key);
66
+ }
67
+
68
+ auto value_for_object::has(v8::Local<v8::Primitive> key) const -> bool {
69
+ return has_property(context(), util::slice(*this), key);
70
+ }
71
+
72
+ auto value_for_object::get(v8::Local<v8::Name> key) const -> mapped_type {
46
73
  return get_property(context(), util::slice(*this), key);
47
74
  }
48
75
 
49
- auto value_for_object::get(v8::Local<v8::Number> key) -> v8::Local<v8::Value> {
76
+ auto value_for_object::get(v8::Local<v8::Number> key) const -> mapped_type {
50
77
  return get_property(context(), util::slice(*this), key);
51
78
  }
52
79
 
53
- auto value_for_object::get(v8::Local<v8::Primitive> key) -> v8::Local<v8::Value> {
80
+ auto value_for_object::get(v8::Local<v8::Primitive> key) const -> mapped_type {
54
81
  return get_property(context(), util::slice(*this), key);
55
82
  }
56
83
 
package/value/object.h.cc CHANGED
@@ -1,6 +1,5 @@
1
1
  export module v8_js:object;
2
2
  import :array;
3
- import :primitive;
4
3
  import auto_js;
5
4
  import std;
6
5
  import v8;
@@ -33,9 +32,12 @@ class value_for_object : public handle_with_context<v8::Object> {
33
32
  using range_type = std::ranges::transform_view<std::views::all_t<const value_for_array&>, iterator_transform>;
34
33
  using iterator = std::ranges::iterator_t<range_type>;
35
34
 
36
- [[nodiscard]] auto get(v8::Local<v8::Name> key) -> v8::Local<v8::Value>;
37
- [[nodiscard]] auto get(v8::Local<v8::Number> key) -> v8::Local<v8::Value>;
38
- [[nodiscard]] auto get(v8::Local<v8::Primitive> key) -> v8::Local<v8::Value>;
35
+ [[nodiscard]] auto get(v8::Local<v8::Name> key) const -> mapped_type;
36
+ [[nodiscard]] auto get(v8::Local<v8::Number> key) const -> mapped_type;
37
+ [[nodiscard]] auto get(v8::Local<v8::Primitive> key) const -> mapped_type;
38
+ [[nodiscard]] auto has(v8::Local<v8::Name> key) const -> bool;
39
+ [[nodiscard]] auto has(v8::Local<v8::Number> key) const -> bool;
40
+ [[nodiscard]] auto has(v8::Local<v8::Primitive> key) const -> bool;
39
41
  [[nodiscard]] auto into_range() -> range_type;
40
42
  [[nodiscard]] auto size() const -> std::size_t;
41
43
 
@@ -1,5 +1,4 @@
1
1
  module v8_js;
2
- import :handle;
3
2
  import :primitive;
4
3
  import std;
5
4
  import v8;
@@ -20,14 +19,6 @@ value_for_number::operator std::int32_t() const {
20
19
  return this->As<v8::Int32>()->Value();
21
20
  }
22
21
 
23
- value_for_number::operator std::int64_t() const {
24
- return this->As<v8::Integer>()->Value();
25
- }
26
-
27
- value_for_number::operator std::uint32_t() const {
28
- return this->As<v8::Uint32>()->Value();
29
- }
30
-
31
22
  // `value_for_bigint`
32
23
  value_for_bigint::operator js::bigint() const {
33
24
  auto bigint = js::bigint{};
@@ -58,18 +49,6 @@ value_for_string::operator std::string() const {
58
49
  return string;
59
50
  }
60
51
 
61
- value_for_string::operator std::u8string() const {
62
- std::u8string string;
63
- string.resize_and_overwrite((*this)->Utf8LengthV2(isolate()), [ this ](char8_t* data, std::size_t length) -> std::size_t {
64
- if (length > 0) {
65
- auto* data_char = reinterpret_cast<char*>(data);
66
- (*this)->WriteUtf8V2(isolate(), data_char, length, v8::String::WriteOptions::NO_NULL_TERMINATION);
67
- }
68
- return length;
69
- });
70
- return string;
71
- }
72
-
73
52
  value_for_string::operator std::u16string() const {
74
53
  std::u16string string;
75
54
  string.resize_and_overwrite((*this)->Length(), [ this ](char16_t* data, std::size_t length) -> std::size_t {
@@ -17,8 +17,6 @@ class value_for_number : public handle_without_lock<v8::Number> {
17
17
  using handle_without_lock<v8::Number>::handle_without_lock;
18
18
  [[nodiscard]] explicit operator double() const;
19
19
  [[nodiscard]] explicit operator std::int32_t() const;
20
- [[nodiscard]] explicit operator std::int64_t() const;
21
- [[nodiscard]] explicit operator std::uint32_t() const;
22
20
  };
23
21
 
24
22
  class value_for_bigint : public handle_without_lock<v8::BigInt> {
@@ -43,7 +41,6 @@ class value_for_string : public handle_with_isolate<v8::String> {
43
41
  public:
44
42
  using handle_with_isolate<v8::String>::handle_with_isolate;
45
43
  [[nodiscard]] explicit operator std::string() const;
46
- [[nodiscard]] explicit operator std::u8string() const;
47
44
  [[nodiscard]] explicit operator std::u16string() const;
48
45
  };
49
46
 
package/value/tag.cc CHANGED
@@ -7,6 +7,7 @@ import v8;
7
7
  namespace js::iv8 {
8
8
 
9
9
  // These helper classes are provided to avoid extra visit inspections on tagged values
10
+ export class Function;
10
11
  export class BigInt64 : public v8::BigInt {};
11
12
  export class BigIntU64 : public v8::BigInt {};
12
13
  export class BigIntWords : public v8::BigInt {};
@@ -19,7 +20,7 @@ export class Undefined : public v8::Primitive {};
19
20
  // `v8::Local<v8::ArrayBuffer>{}->Buffer()` returns a `v8::Local<v8::ArrayBuffer>`, even in the case
20
21
  // it has a `SharedArrayBuffer`. In this case `buffer->IsArrayBuffer()` will return false. This is a
21
22
  // wrapper to denote that there is a data block but we do not know what kind it is.
22
- class DataBlock : public v8::Object {};
23
+ export class DataBlock : public v8::Object {};
23
24
 
24
25
  constexpr auto tag_to_v8_fn = util::overloaded{
25
26
  [](value_tag /*tag*/) -> std::type_identity<v8::Value> { return {}; },
@@ -42,20 +43,26 @@ constexpr auto tag_to_v8_fn = util::overloaded{
42
43
  [](symbol_tag /*tag*/) -> std::type_identity<v8::Symbol> { return {}; },
43
44
 
44
45
  // objects
45
- [](array_buffer_tag /*tag*/) -> std::type_identity<v8::ArrayBuffer> { return {}; },
46
46
  [](date_tag /*tag*/) -> std::type_identity<v8::Date> { return {}; },
47
47
  [](external_tag /*tag*/) -> std::type_identity<v8::External> { return {}; },
48
- [](function_tag /*tag*/) -> std::type_identity<v8::Function> { return {}; },
48
+ [](function_tag /*tag*/) -> std::type_identity<iv8::Function> { return {}; },
49
49
  [](list_tag /*tag*/) -> std::type_identity<v8::Array> { return {}; },
50
50
  [](object_tag /*tag*/) -> std::type_identity<v8::Object> { return {}; },
51
51
  [](promise_tag /*tag*/) -> std::type_identity<v8::Promise> { return {}; },
52
+ [](vector_tag /*tag*/) -> std::type_identity<v8::Array> { return {}; },
53
+
54
+ // data blocks
55
+ [](array_buffer_tag /*tag*/) -> std::type_identity<v8::ArrayBuffer> { return {}; },
56
+ [](data_block_tag /*tag*/) -> std::type_identity<iv8::DataBlock> { return {}; },
52
57
  [](shared_array_buffer_tag /*tag*/) -> std::type_identity<v8::SharedArrayBuffer> { return {}; },
53
58
 
54
59
  // typed arrays
60
+ [](array_buffer_view_tag /*tag*/) -> std::type_identity<v8::ArrayBufferView> { return {}; },
55
61
  [](data_view_tag /*tag*/) -> std::type_identity<v8::DataView> { return {}; },
56
62
  [](typed_array_tag_of<double> /*tag*/) -> std::type_identity<v8::Float64Array> { return {}; },
57
63
  [](typed_array_tag_of<float> /*tag*/) -> std::type_identity<v8::Float32Array> { return {}; },
58
- [](typed_array_tag_of<std::byte> /*tag*/) -> std::type_identity<v8::Uint8ClampedArray> { return {}; },
64
+ [](typed_array_tag_of<js::float16_t> /*tag*/) -> std::type_identity<v8::Float16Array> { return {}; },
65
+ [](typed_array_tag_of<js::uint8_clamped_t> /*tag*/) -> std::type_identity<v8::Uint8ClampedArray> { return {}; },
59
66
  [](typed_array_tag_of<std::int16_t> /*tag*/) -> std::type_identity<v8::Int16Array> { return {}; },
60
67
  [](typed_array_tag_of<std::int32_t> /*tag*/) -> std::type_identity<v8::Int32Array> { return {}; },
61
68
  [](typed_array_tag_of<std::int64_t> /*tag*/) -> std::type_identity<v8::BigInt64Array> { return {}; },
@@ -94,19 +101,25 @@ constexpr auto v8_to_tag_fn = util::overloaded{
94
101
  [](std::type_identity<v8::Uint32> /*type*/) -> number_tag_of<std::uint32_t> { return {}; },
95
102
 
96
103
  // objects
104
+ [](std::type_identity<iv8::Function> /*type*/) -> function_tag { return {}; },
97
105
  [](std::type_identity<v8::Array> /*type*/) -> list_tag { return {}; },
98
- [](std::type_identity<v8::ArrayBuffer> /*type*/) -> array_buffer_tag { return {}; },
99
106
  [](std::type_identity<v8::Date> /*type*/) -> date_tag { return {}; },
100
107
  [](std::type_identity<v8::External> /*type*/) -> external_tag { return {}; },
101
108
  [](std::type_identity<v8::Function> /*type*/) -> function_tag { return {}; },
102
109
  [](std::type_identity<v8::Object> /*type*/) -> object_tag { return {}; },
103
110
  [](std::type_identity<v8::Promise> /*type*/) -> promise_tag { return {}; },
111
+
112
+ // data blocks
113
+ [](std::type_identity<iv8::DataBlock> /*type*/) -> data_block_tag { return {}; },
114
+ [](std::type_identity<v8::ArrayBuffer> /*type*/) -> array_buffer_tag { return {}; },
104
115
  [](std::type_identity<v8::SharedArrayBuffer> /*type*/) -> shared_array_buffer_tag { return {}; },
105
116
 
106
117
  // typed arrays
118
+ [](std::type_identity<v8::ArrayBufferView> /*type*/) -> array_buffer_view_tag { return {}; },
107
119
  [](std::type_identity<v8::BigInt64Array> /*type*/) -> typed_array_tag_of<std::int64_t> { return {}; },
108
120
  [](std::type_identity<v8::BigUint64Array> /*type*/) -> typed_array_tag_of<std::uint64_t> { return {}; },
109
121
  [](std::type_identity<v8::DataView> /*type*/) -> data_view_tag { return {}; },
122
+ [](std::type_identity<v8::Float16Array> /*type*/) -> typed_array_tag_of<js::float16_t> { return {}; },
110
123
  [](std::type_identity<v8::Float32Array> /*type*/) -> typed_array_tag_of<float> { return {}; },
111
124
  [](std::type_identity<v8::Float64Array> /*type*/) -> typed_array_tag_of<double> { return {}; },
112
125
  [](std::type_identity<v8::Int16Array> /*type*/) -> typed_array_tag_of<std::int16_t> { return {}; },
@@ -115,7 +128,7 @@ constexpr auto v8_to_tag_fn = util::overloaded{
115
128
  [](std::type_identity<v8::Uint16Array> /*type*/) -> typed_array_tag_of<std::uint16_t> { return {}; },
116
129
  [](std::type_identity<v8::Uint32Array> /*type*/) -> typed_array_tag_of<std::uint32_t> { return {}; },
117
130
  [](std::type_identity<v8::Uint8Array> /*type*/) -> typed_array_tag_of<std::uint8_t> { return {}; },
118
- [](std::type_identity<v8::Uint8ClampedArray> /*type*/) -> typed_array_tag_of<std::byte> { return {}; },
131
+ [](std::type_identity<v8::Uint8ClampedArray> /*type*/) -> typed_array_tag_of<js::uint8_clamped_t> { return {}; },
119
132
 
120
133
  // templates
121
134
  [](std::type_identity<v8::FunctionTemplate> /*type*/) -> function_prototype_tag { return {}; },
@@ -130,3 +143,9 @@ export template <class Type>
130
143
  using v8_to_tag = decltype(v8_to_tag_fn(type<Type>));
131
144
 
132
145
  } // namespace js::iv8
146
+
147
+ // Specialization for `js::forward`.
148
+ namespace js {
149
+ template <class Type>
150
+ struct forward_tag_for<v8::Local<Type>> : std::type_identity<iv8::v8_to_tag<Type>> {};
151
+ } // namespace js
package/value/value.cc ADDED
@@ -0,0 +1,8 @@
1
+ export module v8_js:value;
2
+ export import :array_buffer;
3
+ export import :array;
4
+ export import :fixed_array;
5
+ export import :function;
6
+ export import :object;
7
+ export import :primitive;
8
+ export import :value.tag;