@lucent-lang/lucent 0.0.4 → 0.1.1
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/README.md +97 -0
- package/app.plugin.js +46 -10
- package/dist/{bench-CR3E7e2e.js → bench-eEez4jhQ.js} +10 -6
- package/dist/{build-CAIrRSYA.js → build-CpUjeHFz.js} +1 -1
- package/dist/{build-check-QozuNJm5.js → build-check-BA1ZEp9s.js} +28 -13
- package/dist/{check-1SCmYlqA.js → check-BZx3FgI6.js} +1 -1
- package/dist/cli.js +62 -13
- package/dist/{codes-CIuwXt1S.js → codes-D-6LxUqD.js} +163 -7
- package/dist/compiler.js +4 -4
- package/dist/{dashboard-B-NzjjaN.js → dashboard-CC-HXhcd.js} +2 -2
- package/dist/{dev-BYWMP7oC.js → dev-DI5yL8zx.js} +62 -23
- package/dist/{diagnostic-BM9sXmwl.js → diagnostic-BvwLZQS1.js} +3 -1
- package/dist/{doctor-C0PrfWT6.js → doctor-CTAX3euc.js} +1 -1
- package/dist/{doctor-DdR4JnVc.js → doctor-CrgOAV5L.js} +1 -1
- package/dist/{explain--vV1oaRl.js → explain-Byit07F-.js} +1 -1
- package/dist/{packages-HyskKIsY.js → packages-CSmKeaAh.js} +2 -33
- package/dist/pipeline-BM_VM2X_.js +700 -0
- package/dist/project-BKNoTEEp.js +342 -0
- package/dist/sdk-coverage-iiv3JqMp.js +113 -0
- package/dist/sdk-diff-ByJ1Gw-F.js +109 -0
- package/dist/sdk-lock-BQn7IyRs.js +38 -0
- package/dist/{sdk-prefetch-mo04JDZV.js → sdk-prefetch-Bv2pNega.js} +2 -2
- package/dist/{sdk-search-Iv4K3-8a.js → sdk-search-CPGJm_Ne.js} +2 -2
- package/dist/{sdk-show-CkrdlqlP.js → sdk-show-BUkLqRnA.js} +5 -4
- package/dist/sdk-usage-0ZFMAYg1.js +95 -0
- package/dist/src-ChnmWLwn.js +40851 -0
- package/dist/trace-Bi4hkmPx.js +139 -0
- package/lib/core.cjs +368 -1
- package/lib/sdk/android.d.ts +54 -1
- package/lib/sdk/compose.d.ts +94 -0
- package/lib/sdk/compose.schemas.json.gz +0 -0
- package/lib/sdk/core.d.ts +201 -0
- package/lib/sdk/ios.d.ts +75 -2
- package/lib/sdk/ui.d.ts +129 -0
- package/metro/transformer.cjs +11 -2
- package/package.json +4 -3
- package/runtime/cpp/lucent/abort.cpp +59 -11
- package/runtime/cpp/lucent/abort.h +22 -6
- package/runtime/cpp/lucent/array.h +12 -2
- package/runtime/cpp/lucent/async.h +101 -21
- package/runtime/cpp/lucent/bigint.cpp +898 -0
- package/runtime/cpp/lucent/bigint.h +302 -0
- package/runtime/cpp/lucent/buffer.cpp +228 -0
- package/runtime/cpp/lucent/buffer.h +328 -0
- package/runtime/cpp/lucent/builtins.cpp +4 -1
- package/runtime/cpp/lucent/bytes.h +21 -2
- package/runtime/cpp/lucent/callback.cpp +29 -0
- package/runtime/cpp/lucent/callback.h +230 -0
- package/runtime/cpp/lucent/compute.cpp +370 -0
- package/runtime/cpp/lucent/compute.h +455 -0
- package/runtime/cpp/lucent/conversions.h +111 -0
- package/runtime/cpp/lucent/core.h +16 -5
- package/runtime/cpp/lucent/equality.h +107 -28
- package/runtime/cpp/lucent/execution.cpp +416 -0
- package/runtime/cpp/lucent/execution.h +270 -0
- package/runtime/cpp/lucent/extension.cpp +97 -0
- package/runtime/cpp/lucent/extension.h +210 -0
- package/runtime/cpp/lucent/helpers.h +12 -5
- package/runtime/cpp/lucent/items.h +52 -0
- package/runtime/cpp/lucent/jserror.cpp +9 -0
- package/runtime/cpp/lucent/jserror.h +11 -0
- package/runtime/cpp/lucent/jsi/convert.cpp +138 -0
- package/runtime/cpp/lucent/jsi/convert.h +128 -59
- package/runtime/cpp/lucent/jsi/host.cpp +213 -35
- package/runtime/cpp/lucent/jsi/host.h +116 -16
- package/runtime/cpp/lucent/json.h +19 -1
- package/runtime/cpp/lucent/lifecycle.cpp +260 -0
- package/runtime/cpp/lucent/lifecycle.h +124 -0
- package/runtime/cpp/lucent/lucent.h +7 -0
- package/runtime/cpp/lucent/map.h +41 -7
- package/runtime/cpp/lucent/native.cpp +35 -47
- package/runtime/cpp/lucent/native.h +116 -26
- package/runtime/cpp/lucent/number.cpp +38 -38
- package/runtime/cpp/lucent/number.h +33 -0
- package/runtime/cpp/lucent/operation.h +65 -0
- package/runtime/cpp/lucent/ops.h +14 -6
- package/runtime/cpp/lucent/platform/android.cpp +223 -10
- package/runtime/cpp/lucent/platform/android.h +227 -4
- package/runtime/cpp/lucent/platform/android_activity.cpp +258 -0
- package/runtime/cpp/lucent/platform/android_requests.h +140 -0
- package/runtime/cpp/lucent/platform/compose.h +256 -0
- package/runtime/cpp/lucent/platform/ios.h +325 -25
- package/runtime/cpp/lucent/platform/ios.mm +1 -14
- package/runtime/cpp/lucent/platform/ios_ui.h +192 -0
- package/runtime/cpp/lucent/platform/ios_ui.mm +454 -0
- package/runtime/cpp/lucent/platform/swiftui.h +190 -0
- package/runtime/cpp/lucent/presentation.cpp +11 -0
- package/runtime/cpp/lucent/presentation.h +109 -0
- package/runtime/cpp/lucent/reactive.cpp +406 -0
- package/runtime/cpp/lucent/reactive.h +566 -0
- package/runtime/cpp/lucent/report.cpp +40 -0
- package/runtime/cpp/lucent/report.h +16 -0
- package/runtime/cpp/lucent/resource.cpp +83 -0
- package/runtime/cpp/lucent/resource.h +75 -0
- package/runtime/cpp/lucent/scheduler.cpp +38 -124
- package/runtime/cpp/lucent/scheduler.h +102 -83
- package/runtime/cpp/lucent/scope.cpp +308 -0
- package/runtime/cpp/lucent/scope.h +452 -0
- package/runtime/cpp/lucent/sizing.h +263 -0
- package/runtime/cpp/lucent/slots.h +231 -0
- package/runtime/cpp/lucent/trace.cpp +539 -0
- package/runtime/cpp/lucent/trace.h +251 -0
- package/runtime/cpp/lucent/transport.cpp +9 -0
- package/runtime/cpp/lucent/transport.h +341 -0
- package/runtime/cpp/lucent/view.cpp +123 -0
- package/runtime/cpp/lucent/view.h +157 -0
- package/runtime/cpp/rn/LucentComponentView.h +121 -0
- package/runtime/cpp/rn/LucentComponentView.mm +479 -0
- package/runtime/cpp/rn/LucentModule.cpp +37 -7
- package/runtime/cpp/rn/LucentModule.h +3 -0
- package/runtime/cpp/rn/LucentViewChildren.h +80 -0
- package/runtime/cpp/rn/LucentViewChildren.mm +211 -0
- package/runtime/cpp/rn/LucentViewRegistry.h +62 -0
- package/runtime/cpp/rn/LucentViewRequests.cpp +91 -0
- package/runtime/cpp/rn/LucentViewRequests.h +104 -0
- package/runtime/cpp/rn/LucentViewSizing.h +345 -0
- package/runtime/cpp/rn/LucentViewSlots.h +242 -0
- package/runtime/cpp/rn/LucentViewValues.h +125 -0
- package/runtime/cpp/rn/LucentViews.h +440 -0
- package/runtime/cpp/rn/LucentViewsAndroid.cpp +439 -0
- package/runtime/cpp/rn/LucentViewsAndroid.h +138 -0
- package/runtime/cpp/third_party/dragonbox/LICENSE-Boost +23 -0
- package/runtime/cpp/third_party/dragonbox/README.md +16 -0
- package/runtime/cpp/third_party/dragonbox/dragonbox.h +4440 -0
- package/runtime/js/index.d.ts +11 -1
- package/runtime/js/index.js +84 -8
- package/runtime/js/views.d.ts +38 -0
- package/runtime/js/views.js +226 -0
- package/runtime/native/android/CMakeLists.txt +4 -1
- package/runtime/native/android/src/compose/java/dev/lucent/compose/CompositionRules.kt +44 -0
- package/runtime/native/android/src/compose/java/dev/lucent/compose/LucentComposition.kt +161 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentActivities.java +292 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentChildren.java +174 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentHostView.java +232 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentInitializer.java +46 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentPackage.java +4 -3
- package/runtime/native/android/src/main/java/dev/lucent/LucentRequestActivity.java +92 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentSlotView.java +102 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentViewManager.java +149 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentViewManagers.java +16 -0
- package/runtime/native/android/src/main/java/dev/lucent/LucentViews.java +44 -0
- package/runtime/test/jsi/harness.cpp +9 -0
- package/schemas/build.schema.json +96 -1
- package/schemas/check.schema.json +56 -1
- package/schemas/lucent.schema.json +495 -9
- package/schemas/sdk-diff.schema.json +70 -0
- package/schemas/sdk-lock.schema.json +67 -0
- package/ts-plugin/index.js +85 -4
- package/dist/pipeline-CH7-2cxu.js +0 -232
- package/dist/project-D8tEet0k.js +0 -150
- package/dist/sdk-coverage-BoW_3Efd.js +0 -64
- package/dist/src-BD7f1_aZ.js +0 -11493
|
@@ -26,6 +26,13 @@ struct ErrorObject : Object {
|
|
|
26
26
|
};
|
|
27
27
|
using Error = Ref<ErrorObject>;
|
|
28
28
|
|
|
29
|
+
/// What a `using` declaration throws when disposing fails while an error is
|
|
30
|
+
/// pending: JavaScript's SuppressedError, with both.
|
|
31
|
+
struct SuppressedErrorObject : ErrorObject {
|
|
32
|
+
Error error;
|
|
33
|
+
Error suppressed;
|
|
34
|
+
};
|
|
35
|
+
|
|
29
36
|
Error makeError(const String& name, const String& message);
|
|
30
37
|
inline Error makeError(const String& message) { return makeError(String::fromLatin1("Error"), message); }
|
|
31
38
|
|
|
@@ -63,4 +70,8 @@ Error currentError(std::exception_ptr ex);
|
|
|
63
70
|
|
|
64
71
|
String errorToString(const Error& e);
|
|
65
72
|
|
|
73
|
+
/// A SuppressedError of `error` (thrown while disposing) and `suppressed` (the
|
|
74
|
+
/// error pending then), as an exception to rethrow.
|
|
75
|
+
std::exception_ptr suppressedError(std::exception_ptr error, std::exception_ptr suppressed);
|
|
76
|
+
|
|
66
77
|
} // namespace lucent
|
|
@@ -27,6 +27,28 @@ void throwBoundaryError(jsi::Runtime& rt, const Path& path, const char* expected
|
|
|
27
27
|
throw jsi::JSError(rt, jsi::Value(rt, err));
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
BigInt Convert<BigInt>::fromJs(jsi::Runtime& rt, const jsi::Value& v, const Path& p) {
|
|
31
|
+
if (!v.isBigInt()) throwBoundaryError(rt, p, "a bigint", v);
|
|
32
|
+
|
|
33
|
+
jsi::BigInt b = v.getBigInt(rt);
|
|
34
|
+
|
|
35
|
+
if (b.isInt64(rt)) return BigInt::fromInt64(b.getInt64(rt));
|
|
36
|
+
if (b.isUint64(rt)) return BigInt::fromUint64(b.getUint64(rt));
|
|
37
|
+
|
|
38
|
+
// Beyond 64 bits: its hex digits, after a "-" when negative.
|
|
39
|
+
return BigInt::fromDigits(b.toString(rt, 16).utf8(rt), 16);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
jsi::Value Convert<BigInt>::toJs(jsi::Runtime& rt, Host&, const BigInt& v) {
|
|
43
|
+
if (auto i = v.tryInt64()) return jsi::Value(jsi::BigInt::fromInt64(rt, *i));
|
|
44
|
+
if (auto u = v.tryUint64()) return jsi::Value(jsi::BigInt::fromUint64(rt, *u));
|
|
45
|
+
|
|
46
|
+
// Beyond 64 bits: BigInt(string) builds it. Decimal, since BigInt()
|
|
47
|
+
// takes no sign before a 0x prefix.
|
|
48
|
+
jsi::Function make = rt.global().getPropertyAsFunction(rt, "BigInt");
|
|
49
|
+
return make.call(rt, jsi::String::createFromAscii(rt, v.toString().toUtf8()));
|
|
50
|
+
}
|
|
51
|
+
|
|
30
52
|
String stringFromJs(jsi::Runtime& rt, const jsi::String& s) {
|
|
31
53
|
// Hermes hands most strings over in one chunk: an ASCII one becomes the
|
|
32
54
|
// String directly (inline when short). Later chunks go to the accumulator.
|
|
@@ -100,6 +122,23 @@ class OwnedBuffer : public jsi::MutableBuffer {
|
|
|
100
122
|
private:
|
|
101
123
|
std::vector<uint8_t> data_;
|
|
102
124
|
};
|
|
125
|
+
|
|
126
|
+
/// Bytes no Lucent code holds (a fresh copy), lent to an ArrayBuffer as they are.
|
|
127
|
+
class FreshBytes : public jsi::MutableBuffer {
|
|
128
|
+
public:
|
|
129
|
+
explicit FreshBytes(Bytes bytes) : bytes_(std::move(bytes)) {}
|
|
130
|
+
size_t size() const override { return bytes_.size(); }
|
|
131
|
+
uint8_t* data() override { return bytes_.data(); }
|
|
132
|
+
const Bytes& bytes() const { return bytes_; }
|
|
133
|
+
|
|
134
|
+
private:
|
|
135
|
+
Bytes bytes_;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
jsi::Value uint8ArrayOver(jsi::Runtime& rt, const std::shared_ptr<FreshBytes>& bytes) {
|
|
139
|
+
jsi::ArrayBuffer ab(rt, bytes);
|
|
140
|
+
return rt.global().getPropertyAsFunction(rt, "Uint8Array").callAsConstructor(rt, ab);
|
|
141
|
+
}
|
|
103
142
|
} // namespace
|
|
104
143
|
|
|
105
144
|
Bytes Convert<Bytes>::fromJs(jsi::Runtime& rt, const jsi::Value& v, const Path& p) {
|
|
@@ -122,6 +161,105 @@ jsi::Value Convert<Bytes>::toJs(jsi::Runtime& rt, Host&, const Bytes& b) {
|
|
|
122
161
|
return rt.global().getPropertyAsFunction(rt, "Uint8Array").callAsConstructor(rt, ab);
|
|
123
162
|
}
|
|
124
163
|
|
|
164
|
+
namespace {
|
|
165
|
+
const char* const kBufferPrototype = "lucent:NativeBuffer";
|
|
166
|
+
|
|
167
|
+
NativeBuffer bufferThis(jsi::Runtime& rt, const jsi::Value& self, const char* method) {
|
|
168
|
+
return Convert<NativeBuffer>::fromJs(rt, self, Path{method, "this"});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
jsi::Function callbackArg(jsi::Runtime& rt, const jsi::Value* args, size_t count, const char* method) {
|
|
172
|
+
const jsi::Value& f = arg(args, count, 0);
|
|
173
|
+
if (!f.isObject() || !f.getObject(rt).isFunction(rt)) throwBoundaryError(rt, Path{method, "argument 0"}, "a function", f);
|
|
174
|
+
|
|
175
|
+
return f.getObject(rt).getFunction(rt);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/// A method of the handle, calling `body(rt, host, buffer, args, count)`.
|
|
179
|
+
template <class F>
|
|
180
|
+
jsi::Function bufferMethod(jsi::Runtime& rt, const char* name, unsigned argc, F body) {
|
|
181
|
+
return jsi::Function::createFromHostFunction(
|
|
182
|
+
rt, jsi::PropNameID::forAscii(rt, name), argc,
|
|
183
|
+
[name, body](jsi::Runtime& rt, const jsi::Value& self, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
184
|
+
Host& host = Host::get(rt);
|
|
185
|
+
return callSync(rt, host, [&] { return body(rt, host, bufferThis(rt, self, name), args, count); });
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
void bufferPrototype(jsi::Runtime& rt, Host&, jsi::Object& proto) {
|
|
190
|
+
defineAccessor(
|
|
191
|
+
rt, proto, "byteLength",
|
|
192
|
+
[](jsi::Runtime& rt, const jsi::Value& self, const jsi::Value*, size_t) {
|
|
193
|
+
return jsi::Value(static_cast<double>(bufferThis(rt, self, "NativeBuffer.byteLength")->size()));
|
|
194
|
+
},
|
|
195
|
+
nullptr);
|
|
196
|
+
|
|
197
|
+
proto.setProperty(rt, "toUint8Array",
|
|
198
|
+
bufferMethod(rt, "toUint8Array", 0, [](jsi::Runtime& rt, Host&, const NativeBuffer& b, const jsi::Value*, size_t) {
|
|
199
|
+
return uint8ArrayOver(rt, std::make_shared<FreshBytes>(b->toBytes()));
|
|
200
|
+
}));
|
|
201
|
+
|
|
202
|
+
proto.setProperty(rt, "withRead",
|
|
203
|
+
bufferMethod(rt, "withRead", 1, [](jsi::Runtime& rt, Host&, const NativeBuffer& b, const jsi::Value* args, size_t count) {
|
|
204
|
+
jsi::Function read = callbackArg(rt, args, count, "withRead");
|
|
205
|
+
|
|
206
|
+
return b->withRead([&](std::span<const uint8_t> bytes) {
|
|
207
|
+
return read.call(rt, uint8ArrayOver(rt, std::make_shared<FreshBytes>(NativeBufferObject::copyOut(bytes))));
|
|
208
|
+
});
|
|
209
|
+
}));
|
|
210
|
+
|
|
211
|
+
proto.setProperty(rt, "withWrite",
|
|
212
|
+
bufferMethod(rt, "withWrite", 1, [](jsi::Runtime& rt, Host&, const NativeBuffer& b, const jsi::Value* args, size_t count) {
|
|
213
|
+
jsi::Function write = callbackArg(rt, args, count, "withWrite");
|
|
214
|
+
|
|
215
|
+
return b->withWrite([&](std::span<uint8_t> bytes) {
|
|
216
|
+
auto lent = std::make_shared<FreshBytes>(NativeBufferObject::copyOut(bytes));
|
|
217
|
+
|
|
218
|
+
// What the callback wrote comes back, even if it then threw.
|
|
219
|
+
struct CopyBack {
|
|
220
|
+
std::span<uint8_t> to;
|
|
221
|
+
const FreshBytes& from;
|
|
222
|
+
~CopyBack() { NativeBufferObject::copyIn(to, from.bytes()); }
|
|
223
|
+
} back{bytes, *lent};
|
|
224
|
+
|
|
225
|
+
return write.call(rt, uint8ArrayOver(rt, lent));
|
|
226
|
+
});
|
|
227
|
+
}));
|
|
228
|
+
|
|
229
|
+
proto.setProperty(rt, "transfer",
|
|
230
|
+
bufferMethod(rt, "transfer", 0, [](jsi::Runtime& rt, Host& host, const NativeBuffer& b, const jsi::Value*, size_t) {
|
|
231
|
+
return Convert<NativeBuffer>::toJs(rt, host, b->transfer());
|
|
232
|
+
}));
|
|
233
|
+
|
|
234
|
+
jsi::Function close = bufferMethod(rt, "close", 0, [](jsi::Runtime&, Host&, const NativeBuffer& b, const jsi::Value*, size_t) {
|
|
235
|
+
b->close();
|
|
236
|
+
return jsi::Value::undefined();
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// `using` in JavaScript, where the runtime has Symbol.dispose.
|
|
240
|
+
jsi::Value dispose = rt.global().getPropertyAsObject(rt, "Symbol").getProperty(rt, "dispose");
|
|
241
|
+
if (dispose.isSymbol()) {
|
|
242
|
+
jsi::Object descriptor(rt);
|
|
243
|
+
descriptor.setProperty(rt, "value", jsi::Value(rt, close));
|
|
244
|
+
descriptor.setProperty(rt, "configurable", true);
|
|
245
|
+
descriptor.setProperty(rt, "writable", true);
|
|
246
|
+
rt.global().getPropertyAsObject(rt, "Object").getPropertyAsFunction(rt, "defineProperty").call(rt, proto, dispose, descriptor);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
proto.setProperty(rt, "close", std::move(close));
|
|
250
|
+
}
|
|
251
|
+
} // namespace
|
|
252
|
+
|
|
253
|
+
NativeBuffer Convert<NativeBuffer>::fromJs(jsi::Runtime& rt, const jsi::Value& v, const Path& p) {
|
|
254
|
+
if (auto b = std::dynamic_pointer_cast<NativeBufferObject>(instanceOf(rt, v))) return b;
|
|
255
|
+
|
|
256
|
+
throwBoundaryError(rt, p, "a NativeBuffer", v);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
jsi::Value Convert<NativeBuffer>::toJs(jsi::Runtime& rt, Host& h, const NativeBuffer& b) {
|
|
260
|
+
return h.wrap(rt, b, kBufferPrototype, bufferPrototype);
|
|
261
|
+
}
|
|
262
|
+
|
|
125
263
|
Error Convert<Error>::fromJs(jsi::Runtime& rt, const jsi::Value& v, const Path&) {
|
|
126
264
|
Error e = makeError(String::fromLatin1("Error"), String());
|
|
127
265
|
if (v.isObject()) {
|
|
@@ -11,10 +11,12 @@
|
|
|
11
11
|
|
|
12
12
|
#include <jsi/jsi.h>
|
|
13
13
|
|
|
14
|
+
#include <optional>
|
|
14
15
|
#include <string>
|
|
15
16
|
#include <vector>
|
|
16
17
|
|
|
17
18
|
#include "../lucent.h"
|
|
19
|
+
#include "../trace.h"
|
|
18
20
|
#include "host.h"
|
|
19
21
|
|
|
20
22
|
namespace lucent::js {
|
|
@@ -109,6 +111,15 @@ struct Convert<String> {
|
|
|
109
111
|
static jsi::Value toJs(jsi::Runtime& rt, Host&, const String& v) { return jsi::Value(stringToJs(rt, v)); }
|
|
110
112
|
};
|
|
111
113
|
|
|
114
|
+
/// Bigints cross exactly: through jsi::BigInt's 64-bit forms when the value
|
|
115
|
+
/// fits (no string, no allocation on the Lucent side), else through its
|
|
116
|
+
/// digits, and the JS side's global BigInt for the value it gets.
|
|
117
|
+
template <>
|
|
118
|
+
struct Convert<BigInt> {
|
|
119
|
+
static BigInt fromJs(jsi::Runtime& rt, const jsi::Value& v, const Path& p);
|
|
120
|
+
static jsi::Value toJs(jsi::Runtime& rt, Host& h, const BigInt& v);
|
|
121
|
+
};
|
|
122
|
+
|
|
112
123
|
template <>
|
|
113
124
|
struct Convert<Undefined> {
|
|
114
125
|
static Undefined fromJs(jsi::Runtime& rt, const jsi::Value& v, const Path& p) {
|
|
@@ -287,6 +298,20 @@ struct Convert<Bytes> {
|
|
|
287
298
|
static jsi::Value toJs(jsi::Runtime& rt, Host& h, const Bytes& b);
|
|
288
299
|
};
|
|
289
300
|
|
|
301
|
+
// --- native buffers ------------------------------------------------------------------------
|
|
302
|
+
|
|
303
|
+
/// A NativeBuffer crosses as an opaque handle, the same JS object for the
|
|
304
|
+
/// same buffer while JavaScript holds it. Its methods mirror lucent:core's:
|
|
305
|
+
/// `byteLength`, `toUint8Array()`, `withRead(f)`, `withWrite(f)`,
|
|
306
|
+
/// `transfer()`, `close()`. JavaScript never gets an ArrayBuffer over the
|
|
307
|
+
/// storage: a borrow lends it a copy (a write borrow copies it back when
|
|
308
|
+
/// the callback returns), counted in the buffer stats.
|
|
309
|
+
template <>
|
|
310
|
+
struct Convert<NativeBuffer> {
|
|
311
|
+
static NativeBuffer fromJs(jsi::Runtime& rt, const jsi::Value& v, const Path& p);
|
|
312
|
+
static jsi::Value toJs(jsi::Runtime& rt, Host& h, const NativeBuffer& b);
|
|
313
|
+
};
|
|
314
|
+
|
|
290
315
|
// --- errors ------------------------------------------------------------------------------
|
|
291
316
|
|
|
292
317
|
template <>
|
|
@@ -338,6 +363,50 @@ struct Convert<AbortSignal> {
|
|
|
338
363
|
|
|
339
364
|
// --- promises ------------------------------------------------------------------------------
|
|
340
365
|
|
|
366
|
+
/// Settles `host`'s JS promise `id` like `p`, once `p` settles: on the JS
|
|
367
|
+
/// thread, where its value converts. If the host is torn down first, the
|
|
368
|
+
/// value is released on the legacy module context instead.
|
|
369
|
+
/// Traced (`traceId`), the result's wait for the JS thread and its
|
|
370
|
+
/// delivery are spans of that id, the delivery named after `site`.
|
|
371
|
+
template <class T>
|
|
372
|
+
void settleLater(Host& host, uint64_t id, const Promise<T>& p, uint64_t traceId = 0, const trace::Site* site = nullptr) {
|
|
373
|
+
std::weak_ptr<Host> weak = host.weak_from_this();
|
|
374
|
+
|
|
375
|
+
p.onSettled([p, weak, id, traceId, site] {
|
|
376
|
+
auto host = weak.lock();
|
|
377
|
+
if (!host) return;
|
|
378
|
+
|
|
379
|
+
trace::Mark wait = traceId ? trace::begin(trace::Category::Queue, "js.wait") : trace::Mark{};
|
|
380
|
+
|
|
381
|
+
host->postToJs([p, id, weak, traceId, site, wait](jsi::Runtime& rt) {
|
|
382
|
+
auto host = weak.lock();
|
|
383
|
+
if (!host) return;
|
|
384
|
+
|
|
385
|
+
trace::end(wait, trace::Category::Queue, "js.wait", {.id = traceId});
|
|
386
|
+
std::optional<trace::Scope> delivery;
|
|
387
|
+
if (traceId) delivery.emplace(trace::Category::Completion, site ? site->name : "completion", site, traceId);
|
|
388
|
+
|
|
389
|
+
LucentScope scope;
|
|
390
|
+
if (!p.fulfilled()) {
|
|
391
|
+
host->reject(rt, id, host->errorToJs(rt, p.error()));
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
jsi::Value value = jsi::Value::undefined();
|
|
396
|
+
if constexpr (!std::is_void_v<T>) {
|
|
397
|
+
try {
|
|
398
|
+
value = Convert<T>::toJs(rt, *host, p.value());
|
|
399
|
+
} catch (const jsi::JSError& e) {
|
|
400
|
+
host->reject(rt, id, jsi::Value(rt, e.value()));
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
host->resolve(rt, id, value);
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
|
|
341
410
|
/// Hands a Lucent promise to JavaScript: the JS promise settles on the JS
|
|
342
411
|
/// thread when the Lucent one does.
|
|
343
412
|
template <class T>
|
|
@@ -345,32 +414,7 @@ struct Convert<Promise<T>> {
|
|
|
345
414
|
static jsi::Value toJs(jsi::Runtime& rt, Host& h, const Promise<T>& p) {
|
|
346
415
|
uint64_t id = 0;
|
|
347
416
|
jsi::Value jsPromise = h.createPromise(rt, id);
|
|
348
|
-
|
|
349
|
-
p.onSettled([p, weak, id] {
|
|
350
|
-
auto host = weak.lock();
|
|
351
|
-
if (!host) return;
|
|
352
|
-
host->postToJs([p, id, weak](jsi::Runtime& rt) {
|
|
353
|
-
auto host = weak.lock();
|
|
354
|
-
if (!host) return;
|
|
355
|
-
LucentScope scope;
|
|
356
|
-
if (p.fulfilled()) {
|
|
357
|
-
jsi::Value value = jsi::Value::undefined();
|
|
358
|
-
try {
|
|
359
|
-
if constexpr (std::is_void_v<T>) {
|
|
360
|
-
value = jsi::Value::undefined();
|
|
361
|
-
} else {
|
|
362
|
-
value = Convert<T>::toJs(rt, *host, p.value());
|
|
363
|
-
}
|
|
364
|
-
} catch (const jsi::JSError& e) {
|
|
365
|
-
host->reject(rt, id, jsi::Value(rt, e.value()));
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
host->resolve(rt, id, value);
|
|
369
|
-
} else {
|
|
370
|
-
host->reject(rt, id, host->errorToJs(rt, p.error()));
|
|
371
|
-
}
|
|
372
|
-
});
|
|
373
|
-
});
|
|
417
|
+
settleLater(h, id, p);
|
|
374
418
|
return jsPromise;
|
|
375
419
|
}
|
|
376
420
|
/// A JS promise passed into Lucent (e.g. returned by a callback).
|
|
@@ -415,7 +459,7 @@ struct Convert<Fn<R(A...)>> {
|
|
|
415
459
|
auto host = cb->host();
|
|
416
460
|
if (!host || !host->alive()) {
|
|
417
461
|
if constexpr (std::is_void_v<R>) return;
|
|
418
|
-
else throwError(
|
|
462
|
+
else throwError(Host::goneError());
|
|
419
463
|
}
|
|
420
464
|
if (host->onJsThread()) {
|
|
421
465
|
jsi::Runtime& rt = host->runtime();
|
|
@@ -450,6 +494,8 @@ struct Convert<Fn<R(A...)>> {
|
|
|
450
494
|
return;
|
|
451
495
|
} else if constexpr (IsPromiseType<R>::value) {
|
|
452
496
|
R out;
|
|
497
|
+
// If the task never runs (the runtime went), the promise rejects.
|
|
498
|
+
auto gone = [out] { out.reject(Host::goneError()); };
|
|
453
499
|
host->postToJs([cb, out, where, args...](jsi::Runtime& rt) mutable {
|
|
454
500
|
auto host = cb->host();
|
|
455
501
|
jsi::Function* fn = host ? host->retained(cb->id()) : nullptr;
|
|
@@ -474,7 +520,7 @@ struct Convert<Fn<R(A...)>> {
|
|
|
474
520
|
} catch (const Exception& e) {
|
|
475
521
|
out.reject(e.error());
|
|
476
522
|
}
|
|
477
|
-
});
|
|
523
|
+
}, gone);
|
|
478
524
|
return out;
|
|
479
525
|
} else {
|
|
480
526
|
throwError(String::fromLatin1("Error"),
|
|
@@ -487,13 +533,14 @@ struct Convert<Fn<R(A...)>> {
|
|
|
487
533
|
return jsi::Function::createFromHostFunction(
|
|
488
534
|
rt, jsi::PropNameID::forAscii(rt, "lucentFunction"), sizeof...(A),
|
|
489
535
|
[f, weak](jsi::Runtime& rt, const jsi::Value&, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
490
|
-
|
|
491
|
-
|
|
536
|
+
// A torn-down host's function answers through the runtime's host.
|
|
537
|
+
auto kept = weak.lock();
|
|
538
|
+
Host& host = kept && kept->alive() ? *kept : Host::get(rt);
|
|
492
539
|
LucentScope scope;
|
|
493
540
|
try {
|
|
494
|
-
return call(rt,
|
|
541
|
+
return call(rt, host, f, args, count, std::index_sequence_for<A...>{});
|
|
495
542
|
} catch (const Exception& e) {
|
|
496
|
-
throw jsi::JSError(rt, host
|
|
543
|
+
throw jsi::JSError(rt, host.errorToJs(rt, e.error()));
|
|
497
544
|
}
|
|
498
545
|
});
|
|
499
546
|
}
|
|
@@ -521,10 +568,22 @@ Promise<T> Convert<Promise<T>>::fromJs(jsi::Runtime& rt, const jsi::Value& v, co
|
|
|
521
568
|
else out.resolve(Convert<T>::fromJs(rt, v, p));
|
|
522
569
|
return out;
|
|
523
570
|
}
|
|
571
|
+
|
|
572
|
+
// Rejected if the runtime's host is torn down before JavaScript settles
|
|
573
|
+
// it, so what awaits it goes on (and releases what it holds).
|
|
574
|
+
const std::shared_ptr<Scope>& scope = Host::get(rt).scope();
|
|
575
|
+
Scope::CleanupId pending = scope->onDispose([out] { out.reject(Host::goneError()); });
|
|
576
|
+
if (pending == 0) return out;
|
|
577
|
+
|
|
578
|
+
auto settled = [owner = std::weak_ptr<Scope>(scope), pending] {
|
|
579
|
+
if (auto s = owner.lock()) s->remove(pending);
|
|
580
|
+
};
|
|
581
|
+
|
|
524
582
|
std::string where = std::string(p.fn) + " " + p.where();
|
|
525
583
|
auto onFulfilled = jsi::Function::createFromHostFunction(
|
|
526
584
|
rt, jsi::PropNameID::forAscii(rt, "onFulfilled"), 1,
|
|
527
|
-
[out, where](jsi::Runtime& rt, const jsi::Value&, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
585
|
+
[out, where, settled](jsi::Runtime& rt, const jsi::Value&, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
586
|
+
settled();
|
|
528
587
|
LucentScope scope;
|
|
529
588
|
try {
|
|
530
589
|
if constexpr (std::is_void_v<T>) out.resolve(undefined);
|
|
@@ -536,7 +595,8 @@ Promise<T> Convert<Promise<T>>::fromJs(jsi::Runtime& rt, const jsi::Value& v, co
|
|
|
536
595
|
});
|
|
537
596
|
auto onRejected = jsi::Function::createFromHostFunction(
|
|
538
597
|
rt, jsi::PropNameID::forAscii(rt, "onRejected"), 1,
|
|
539
|
-
[out](jsi::Runtime& rt, const jsi::Value&, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
598
|
+
[out, settled](jsi::Runtime& rt, const jsi::Value&, const jsi::Value* args, size_t count) -> jsi::Value {
|
|
599
|
+
settled();
|
|
540
600
|
LucentScope scope;
|
|
541
601
|
out.reject(Convert<Error>::fromJs(rt, arg(args, count, 0), Path{"promise", "rejection"}));
|
|
542
602
|
return jsi::Value::undefined();
|
|
@@ -551,6 +611,17 @@ Promise<T> Convert<Promise<T>>::fromJs(jsi::Runtime& rt, const jsi::Value& v, co
|
|
|
551
611
|
|
|
552
612
|
/// Runs a synchronous Lucent call from JS, translating Lucent errors into
|
|
553
613
|
/// JS exceptions.
|
|
614
|
+
template <class F>
|
|
615
|
+
jsi::Value callSync(jsi::Runtime& rt, Host& host, F&& body);
|
|
616
|
+
|
|
617
|
+
/// A synchronous call from JS, traced as an entry at the export's site
|
|
618
|
+
/// (the compiler passes it: LUCENT_TRACE_SITE_AT).
|
|
619
|
+
template <class F>
|
|
620
|
+
jsi::Value callSync(jsi::Runtime& rt, Host& host, const trace::Site* site, F&& body) {
|
|
621
|
+
trace::Scope entry(trace::Category::Entry, site->name, site);
|
|
622
|
+
return callSync(rt, host, std::forward<F>(body));
|
|
623
|
+
}
|
|
624
|
+
|
|
554
625
|
template <class F>
|
|
555
626
|
jsi::Value callSync(jsi::Runtime& rt, Host& host, F&& body) {
|
|
556
627
|
LucentScope scope;
|
|
@@ -569,43 +640,41 @@ jsi::Value callSync(jsi::Runtime& rt, Host& host, F&& body) {
|
|
|
569
640
|
|
|
570
641
|
/// Starts an exported async function on the Lucent thread and returns a JS
|
|
571
642
|
/// promise for its result. `start` runs on the Lucent thread and returns the
|
|
572
|
-
/// Lucent promise.
|
|
643
|
+
/// Lucent promise; it does not start if the host is torn down first.
|
|
573
644
|
template <class T, class F>
|
|
574
645
|
jsi::Value callAsync(jsi::Runtime& rt, Host& host, F&& start) {
|
|
646
|
+
return callAsync<T>(rt, host, nullptr, std::forward<F>(start));
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/// As above, traced from the export's `site`: the call, the job it posts
|
|
650
|
+
/// (its wait and its run), the result's wait for the JS thread and its
|
|
651
|
+
/// delivery share one id.
|
|
652
|
+
template <class T, class F>
|
|
653
|
+
jsi::Value callAsync(jsi::Runtime& rt, Host& host, const trace::Site* site, F&& start) {
|
|
654
|
+
uint64_t traceId = site && trace::enabled() ? trace::newId() : 0;
|
|
655
|
+
|
|
656
|
+
std::optional<trace::Scope> entry;
|
|
657
|
+
std::optional<trace::Correlate> correlate;
|
|
658
|
+
if (traceId) [[unlikely]] {
|
|
659
|
+
entry.emplace(trace::Category::Entry, site->name, site, traceId);
|
|
660
|
+
correlate.emplace(traceId);
|
|
661
|
+
}
|
|
662
|
+
|
|
575
663
|
uint64_t id = 0;
|
|
576
664
|
jsi::Value jsPromise = host.createPromise(rt, id);
|
|
577
665
|
std::weak_ptr<Host> weak = host.weak_from_this();
|
|
578
|
-
|
|
666
|
+
|
|
667
|
+
host.postToModule([weak, id, traceId, site, start = std::forward<F>(start)]() mutable {
|
|
579
668
|
Promise<T> p;
|
|
580
669
|
try {
|
|
581
670
|
p = start();
|
|
582
671
|
} catch (...) {
|
|
583
672
|
p = Promise<T>::rejected(currentError(std::current_exception()));
|
|
584
673
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
if (!host) return;
|
|
588
|
-
host->postToJs([p, id, weak](jsi::Runtime& rt) {
|
|
589
|
-
auto host = weak.lock();
|
|
590
|
-
if (!host) return;
|
|
591
|
-
LucentScope scope;
|
|
592
|
-
if (p.fulfilled()) {
|
|
593
|
-
jsi::Value value = jsi::Value::undefined();
|
|
594
|
-
if constexpr (!std::is_void_v<T>) {
|
|
595
|
-
try {
|
|
596
|
-
value = Convert<T>::toJs(rt, *host, p.value());
|
|
597
|
-
} catch (const jsi::JSError& e) {
|
|
598
|
-
host->reject(rt, id, jsi::Value(rt, e.value()));
|
|
599
|
-
return;
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
host->resolve(rt, id, value);
|
|
603
|
-
} else {
|
|
604
|
-
host->reject(rt, id, host->errorToJs(rt, p.error()));
|
|
605
|
-
}
|
|
606
|
-
});
|
|
607
|
-
});
|
|
674
|
+
|
|
675
|
+
if (auto host = weak.lock()) settleLater(*host, id, p, traceId, site);
|
|
608
676
|
});
|
|
677
|
+
|
|
609
678
|
return jsPromise;
|
|
610
679
|
}
|
|
611
680
|
|