@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 +3 -0
- package/_module.cc +2 -5
- package/package.json +3 -3
- package/support/callback.cc +1 -1
- package/support/callback_storage.cc +3 -6
- package/support/lock.cc +0 -4
- package/support/lock.h.cc +4 -1
- package/transfer/accept.cc +4 -4
- package/transfer/accept.h.cc +79 -11
- package/transfer/visit.cc +106 -43
- package/value/array_buffer.cc +0 -13
- package/value/array_buffer.h.cc +15 -5
- package/value/function.cc +41 -0
- package/value/function.h.cc +16 -0
- package/value/object.cc +34 -7
- package/value/object.h.cc +6 -4
- package/value/primitive.cc +0 -21
- package/value/primitive.h.cc +0 -3
- package/value/tag.cc +25 -6
- package/value/value.cc +8 -0
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 :
|
|
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.
|
|
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.
|
|
9
|
-
"@auto_js/v8_exports": "^0.0.
|
|
8
|
+
"@auto_js/js": "^0.0.5",
|
|
9
|
+
"@auto_js/v8_exports": "^0.0.3"
|
|
10
10
|
},
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
package/support/callback.cc
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
|
36
|
-
auto
|
|
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:
|
package/transfer/accept.cc
CHANGED
|
@@ -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<
|
|
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.
|
|
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.
|
|
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
|
package/transfer/accept.h.cc
CHANGED
|
@@ -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 :
|
|
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<
|
|
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::
|
|
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<
|
|
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<
|
|
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(
|
|
364
|
-
|
|
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::
|
|
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::
|
|
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->
|
|
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->
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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::
|
|
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::
|
|
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 (
|
|
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 (
|
|
222
|
-
template <class Accept>
|
|
223
|
-
|
|
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
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
|
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<
|
|
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::
|
|
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::
|
|
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::
|
|
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
|
package/value/array_buffer.cc
CHANGED
|
@@ -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
|
package/value/array_buffer.h.cc
CHANGED
|
@@ -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
|
-
|
|
15
|
-
explicit operator
|
|
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 :
|
|
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::
|
|
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) ->
|
|
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) ->
|
|
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) ->
|
|
37
|
-
[[nodiscard]] auto get(v8::Local<v8::Number> key) ->
|
|
38
|
-
[[nodiscard]] auto get(v8::Local<v8::Primitive> key) ->
|
|
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
|
|
package/value/primitive.cc
CHANGED
|
@@ -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 {
|
package/value/primitive.h.cc
CHANGED
|
@@ -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<
|
|
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<
|
|
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<
|
|
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
|