@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
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#include "lifecycle.h"
|
|
2
|
+
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <atomic>
|
|
5
|
+
#include <map>
|
|
6
|
+
#include <mutex>
|
|
7
|
+
#include <stdexcept>
|
|
8
|
+
#include <string>
|
|
9
|
+
|
|
10
|
+
#include "execution.h"
|
|
11
|
+
#include "report.h"
|
|
12
|
+
|
|
13
|
+
namespace lucent {
|
|
14
|
+
|
|
15
|
+
namespace detail {
|
|
16
|
+
|
|
17
|
+
/// One subscription's listener. `live` turns false when it closes, so a
|
|
18
|
+
/// report that already took it skips it.
|
|
19
|
+
struct LifecycleListener {
|
|
20
|
+
enum class Kind : uint8_t { App, Scene };
|
|
21
|
+
|
|
22
|
+
Kind kind;
|
|
23
|
+
uint8_t event;
|
|
24
|
+
Lifecycle::AppListener app;
|
|
25
|
+
Lifecycle::SceneListener scene;
|
|
26
|
+
std::atomic<bool> live{true};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
struct LifecycleState {
|
|
30
|
+
struct Scene {
|
|
31
|
+
SceneId id;
|
|
32
|
+
/// When it last connected or activated: the order of scenes().
|
|
33
|
+
uint64_t touched;
|
|
34
|
+
std::shared_ptr<Scope> scope;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
struct Subscription {
|
|
38
|
+
std::shared_ptr<LifecycleListener> listener;
|
|
39
|
+
/// Kept here: the subscription lasts until it closes, not until its
|
|
40
|
+
/// handle goes.
|
|
41
|
+
std::shared_ptr<Resource> handle;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
mutable std::mutex m;
|
|
45
|
+
std::vector<Scene> scenes;
|
|
46
|
+
uint64_t touches = 0;
|
|
47
|
+
uint64_t nextSubscription = 1;
|
|
48
|
+
// Keyed by id, so listeners run in subscription order.
|
|
49
|
+
std::map<uint64_t, Subscription> subscriptions;
|
|
50
|
+
|
|
51
|
+
Scene* find(SceneId id) {
|
|
52
|
+
auto it = std::find_if(scenes.begin(), scenes.end(), [id](const Scene& s) { return s.id == id; });
|
|
53
|
+
return it == scenes.end() ? nullptr : &*it;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/// The open listeners of an event, in subscription order.
|
|
57
|
+
std::vector<std::shared_ptr<LifecycleListener>> listenersOf(LifecycleListener::Kind kind, uint8_t event) const {
|
|
58
|
+
std::lock_guard<std::mutex> g(m);
|
|
59
|
+
std::vector<std::shared_ptr<LifecycleListener>> out;
|
|
60
|
+
|
|
61
|
+
for (const auto& [id, s] : subscriptions)
|
|
62
|
+
if (s.listener->kind == kind && s.listener->event == event) out.push_back(s.listener);
|
|
63
|
+
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
} // namespace detail
|
|
69
|
+
|
|
70
|
+
namespace {
|
|
71
|
+
|
|
72
|
+
// Constant-initialized: safe to use during static initialization.
|
|
73
|
+
std::atomic<SceneId> nextScene{1};
|
|
74
|
+
|
|
75
|
+
void requireMain(const char* what) {
|
|
76
|
+
if (!onMainThread()) throw std::logic_error(std::string("Lifecycle::") + what + " is reported on the main thread");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// Runs the listeners a report took, skipping those closed since.
|
|
80
|
+
void run(const std::vector<std::shared_ptr<detail::LifecycleListener>>& listeners, SceneId scene) {
|
|
81
|
+
for (const auto& l : listeners) {
|
|
82
|
+
if (!l->live.load(std::memory_order_acquire)) continue;
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
if (l->kind == detail::LifecycleListener::Kind::App) {
|
|
86
|
+
l->app();
|
|
87
|
+
} else {
|
|
88
|
+
l->scene(scene);
|
|
89
|
+
}
|
|
90
|
+
} catch (...) {
|
|
91
|
+
reportUncaught(std::current_exception(), "lifecycle listener");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
} // namespace
|
|
97
|
+
|
|
98
|
+
Lifecycle::Lifecycle() : state_(std::make_shared<detail::LifecycleState>()) {}
|
|
99
|
+
|
|
100
|
+
Lifecycle::~Lifecycle() {
|
|
101
|
+
std::vector<detail::LifecycleState::Scene> scenes;
|
|
102
|
+
std::map<uint64_t, detail::LifecycleState::Subscription> subscriptions;
|
|
103
|
+
{
|
|
104
|
+
std::lock_guard<std::mutex> g(state_->m);
|
|
105
|
+
scenes.swap(state_->scenes);
|
|
106
|
+
subscriptions.swap(state_->subscriptions);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
for (auto& [id, s] : subscriptions) s.listener->live.store(false, std::memory_order_release);
|
|
110
|
+
|
|
111
|
+
for (auto& scene : scenes)
|
|
112
|
+
if (auto e = scene.scope->dispose()) reportUncaught(e, "scene");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
Lifecycle& Lifecycle::shared() {
|
|
116
|
+
// Never destroyed: the platform may report while the process exits.
|
|
117
|
+
static auto* lifecycle = new Lifecycle();
|
|
118
|
+
return *lifecycle;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
SceneId Lifecycle::connect() {
|
|
122
|
+
requireMain("connect");
|
|
123
|
+
|
|
124
|
+
SceneId id = nextScene.fetch_add(1);
|
|
125
|
+
|
|
126
|
+
std::lock_guard<std::mutex> g(state_->m);
|
|
127
|
+
state_->scenes.push_back({id, ++state_->touches, Scope::create(0)});
|
|
128
|
+
|
|
129
|
+
return id;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
void Lifecycle::report(SceneId scene, SceneEvent event) {
|
|
133
|
+
requireMain("report");
|
|
134
|
+
|
|
135
|
+
{
|
|
136
|
+
std::lock_guard<std::mutex> g(state_->m);
|
|
137
|
+
detail::LifecycleState::Scene* known = state_->find(scene);
|
|
138
|
+
if (!known) return;
|
|
139
|
+
|
|
140
|
+
if (event == SceneEvent::DidActivate) known->touched = ++state_->touches;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
run(state_->listenersOf(detail::LifecycleListener::Kind::Scene, static_cast<uint8_t>(event)), scene);
|
|
144
|
+
|
|
145
|
+
if (event != SceneEvent::DidDisconnect) return;
|
|
146
|
+
|
|
147
|
+
std::shared_ptr<Scope> scope;
|
|
148
|
+
{
|
|
149
|
+
std::lock_guard<std::mutex> g(state_->m);
|
|
150
|
+
auto& scenes = state_->scenes;
|
|
151
|
+
auto it = std::find_if(scenes.begin(), scenes.end(), [scene](const auto& s) { return s.id == scene; });
|
|
152
|
+
if (it == scenes.end()) return;
|
|
153
|
+
|
|
154
|
+
scope = std::move(it->scope);
|
|
155
|
+
scenes.erase(it);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (auto e = scope->dispose()) reportUncaught(e, "scene");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
void Lifecycle::report(AppEvent event) {
|
|
162
|
+
requireMain("report");
|
|
163
|
+
|
|
164
|
+
run(state_->listenersOf(detail::LifecycleListener::Kind::App, static_cast<uint8_t>(event)), 0);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
std::vector<SceneId> Lifecycle::scenes() const {
|
|
168
|
+
std::vector<detail::LifecycleState::Scene> scenes;
|
|
169
|
+
{
|
|
170
|
+
std::lock_guard<std::mutex> g(state_->m);
|
|
171
|
+
scenes = state_->scenes;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
std::sort(scenes.begin(), scenes.end(), [](const auto& a, const auto& b) { return a.touched > b.touched; });
|
|
175
|
+
|
|
176
|
+
std::vector<SceneId> out;
|
|
177
|
+
for (const auto& s : scenes) out.push_back(s.id);
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
std::shared_ptr<Scope> Lifecycle::sceneScope(SceneId scene) const {
|
|
182
|
+
std::lock_guard<std::mutex> g(state_->m);
|
|
183
|
+
detail::LifecycleState::Scene* known = state_->find(scene);
|
|
184
|
+
|
|
185
|
+
return known ? known->scope : nullptr;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
std::shared_ptr<Resource> Lifecycle::subscribe(AppEvent event, AppListener listener, const std::shared_ptr<Scope>& scope) {
|
|
189
|
+
if (!listener) throw std::invalid_argument("A lifecycle listener must be a function");
|
|
190
|
+
|
|
191
|
+
auto l = std::make_shared<detail::LifecycleListener>();
|
|
192
|
+
l->kind = detail::LifecycleListener::Kind::App;
|
|
193
|
+
l->event = static_cast<uint8_t>(event);
|
|
194
|
+
l->app = std::move(listener);
|
|
195
|
+
|
|
196
|
+
return add(std::move(l), scope);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
std::shared_ptr<Resource> Lifecycle::subscribe(SceneEvent event, SceneListener listener, const std::shared_ptr<Scope>& scope) {
|
|
200
|
+
if (!listener) throw std::invalid_argument("A lifecycle listener must be a function");
|
|
201
|
+
|
|
202
|
+
auto l = std::make_shared<detail::LifecycleListener>();
|
|
203
|
+
l->kind = detail::LifecycleListener::Kind::Scene;
|
|
204
|
+
l->event = static_cast<uint8_t>(event);
|
|
205
|
+
l->scene = std::move(listener);
|
|
206
|
+
|
|
207
|
+
return add(std::move(l), scope);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
std::shared_ptr<Resource> Lifecycle::add(std::shared_ptr<detail::LifecycleListener> listener, const std::shared_ptr<Scope>& scope) {
|
|
211
|
+
uint64_t id;
|
|
212
|
+
{
|
|
213
|
+
std::lock_guard<std::mutex> g(state_->m);
|
|
214
|
+
id = state_->nextSubscription++;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
std::weak_ptr<detail::LifecycleState> weak = state_;
|
|
218
|
+
auto release = [weak, listener, id] {
|
|
219
|
+
listener->live.store(false, std::memory_order_release);
|
|
220
|
+
|
|
221
|
+
// Taken out under the lock and destroyed after it: the listener's
|
|
222
|
+
// captures, and the table's reference to this subscription.
|
|
223
|
+
detail::LifecycleState::Subscription removed;
|
|
224
|
+
if (auto state = weak.lock()) {
|
|
225
|
+
std::lock_guard<std::mutex> g(state->m);
|
|
226
|
+
auto it = state->subscriptions.find(id);
|
|
227
|
+
if (it == state->subscriptions.end()) return;
|
|
228
|
+
|
|
229
|
+
removed = std::move(it->second);
|
|
230
|
+
state->subscriptions.erase(it);
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// Opened first: under a scope that has ended, it closes at once, before
|
|
235
|
+
// it is ever listed.
|
|
236
|
+
std::shared_ptr<Resource> handle = Resource::open(String::fromLatin1("Lifecycle subscription"), std::move(release), nullptr, scope);
|
|
237
|
+
if (!handle->isOpen()) return handle;
|
|
238
|
+
|
|
239
|
+
std::lock_guard<std::mutex> g(state_->m);
|
|
240
|
+
// Closed by its scope on another thread in the meantime: never listed.
|
|
241
|
+
if (!listener->live.load(std::memory_order_acquire)) return handle;
|
|
242
|
+
|
|
243
|
+
state_->subscriptions.emplace(id, detail::LifecycleState::Subscription{std::move(listener), handle});
|
|
244
|
+
return handle;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
size_t Lifecycle::subscriptions() const {
|
|
248
|
+
std::lock_guard<std::mutex> g(state_->m);
|
|
249
|
+
return state_->subscriptions.size();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
std::optional<SceneId> presentingScene(const std::vector<SceneId>& scenes, const std::function<SceneState(SceneId)>& stateOf) {
|
|
253
|
+
for (SceneState wanted : {SceneState::ForegroundActive, SceneState::ForegroundInactive})
|
|
254
|
+
for (SceneId s : scenes)
|
|
255
|
+
if (stateOf(s) == wanted) return s;
|
|
256
|
+
|
|
257
|
+
return std::nullopt;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
} // namespace lucent
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// Lucent runtime — the app's and its scenes' lifecycle.
|
|
2
|
+
//
|
|
3
|
+
// The platform adapter (lucent/platform/ios_ui.mm) reports what the
|
|
4
|
+
// platform posts, on the main thread: the app becoming active or going to
|
|
5
|
+
// the background, and each scene connecting, activating, and
|
|
6
|
+
// disconnecting. Lucent code subscribes to those events. Nothing here
|
|
7
|
+
// knows UIKit: a scene is a SceneId, never a pointer, so nothing here can
|
|
8
|
+
// keep a window or view controller alive.
|
|
9
|
+
//
|
|
10
|
+
// Each connected scene has a scope, disposed when the scene disconnects:
|
|
11
|
+
// work tied to what the scene shows (a presentation, say) ends with it.
|
|
12
|
+
#pragma once
|
|
13
|
+
|
|
14
|
+
#include <cstdint>
|
|
15
|
+
#include <functional>
|
|
16
|
+
#include <memory>
|
|
17
|
+
#include <optional>
|
|
18
|
+
#include <vector>
|
|
19
|
+
|
|
20
|
+
#include "resource.h"
|
|
21
|
+
#include "scope.h"
|
|
22
|
+
|
|
23
|
+
namespace lucent {
|
|
24
|
+
|
|
25
|
+
/// Process-unique and never reused; 0 is none.
|
|
26
|
+
using SceneId = uint64_t;
|
|
27
|
+
|
|
28
|
+
/// UIApplication's lifecycle notifications.
|
|
29
|
+
enum class AppEvent : uint8_t {
|
|
30
|
+
DidBecomeActive,
|
|
31
|
+
WillResignActive,
|
|
32
|
+
DidEnterBackground,
|
|
33
|
+
WillEnterForeground,
|
|
34
|
+
DidReceiveMemoryWarning,
|
|
35
|
+
WillTerminate,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/// UIScene's lifecycle notifications.
|
|
39
|
+
enum class SceneEvent : uint8_t {
|
|
40
|
+
WillConnect,
|
|
41
|
+
DidDisconnect,
|
|
42
|
+
DidActivate,
|
|
43
|
+
WillDeactivate,
|
|
44
|
+
WillEnterForeground,
|
|
45
|
+
DidEnterBackground,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/// UIScene.ActivationState.
|
|
49
|
+
enum class SceneState : uint8_t { Unattached, ForegroundActive, ForegroundInactive, Background };
|
|
50
|
+
|
|
51
|
+
namespace detail {
|
|
52
|
+
struct LifecycleState;
|
|
53
|
+
struct LifecycleListener;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/// What the platform reported, and who listens. Construction does nothing
|
|
57
|
+
/// else; destruction disposes the scopes of the scenes still connected.
|
|
58
|
+
class Lifecycle {
|
|
59
|
+
public:
|
|
60
|
+
using AppListener = std::function<void()>;
|
|
61
|
+
using SceneListener = std::function<void(SceneId)>;
|
|
62
|
+
|
|
63
|
+
Lifecycle();
|
|
64
|
+
~Lifecycle();
|
|
65
|
+
|
|
66
|
+
Lifecycle(const Lifecycle&) = delete;
|
|
67
|
+
Lifecycle& operator=(const Lifecycle&) = delete;
|
|
68
|
+
|
|
69
|
+
/// The process's, which the platform adapter reports to.
|
|
70
|
+
static Lifecycle& shared();
|
|
71
|
+
|
|
72
|
+
// --- what the platform reports: on the main thread only (std::logic_error
|
|
73
|
+
// elsewhere) -------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
/// A scene the platform connected, or found connected: its new id, and a
|
|
76
|
+
/// scope for it. Nothing is announced: the platform reports WillConnect
|
|
77
|
+
/// once it can name the scene.
|
|
78
|
+
SceneId connect();
|
|
79
|
+
|
|
80
|
+
/// Runs the event's listeners with the scene. DidActivate makes it the
|
|
81
|
+
/// most recently activated; DidDisconnect, after the listeners ran,
|
|
82
|
+
/// disposes its scope and forgets it. A scene it does not know is
|
|
83
|
+
/// ignored.
|
|
84
|
+
void report(SceneId scene, SceneEvent event);
|
|
85
|
+
|
|
86
|
+
void report(AppEvent event);
|
|
87
|
+
|
|
88
|
+
// --- what it knows: any thread ------------------------------------------
|
|
89
|
+
|
|
90
|
+
/// The connected scenes, most recently activated first (or, until
|
|
91
|
+
/// activated, connected).
|
|
92
|
+
std::vector<SceneId> scenes() const;
|
|
93
|
+
|
|
94
|
+
/// The scene's scope while it is connected, else null.
|
|
95
|
+
std::shared_ptr<Scope> sceneScope(SceneId scene) const;
|
|
96
|
+
|
|
97
|
+
// --- subscriptions: any thread ------------------------------------------
|
|
98
|
+
|
|
99
|
+
/// Calls `listener` on each `event`, on the main thread, from the next
|
|
100
|
+
/// report on. The subscription is open until it is closed or `scope` is
|
|
101
|
+
/// disposed (under a scope that has ended, it is closed at once);
|
|
102
|
+
/// dropping the handle does not end it. Closed on the main thread, its
|
|
103
|
+
/// listener never runs again; closed on another thread while an event is
|
|
104
|
+
/// being reported, it may still hear that event (closing never waits).
|
|
105
|
+
/// What a listener throws is reported (reportUncaught), and the rest
|
|
106
|
+
/// still run.
|
|
107
|
+
std::shared_ptr<Resource> subscribe(AppEvent event, AppListener listener, const std::shared_ptr<Scope>& scope = nullptr);
|
|
108
|
+
std::shared_ptr<Resource> subscribe(SceneEvent event, SceneListener listener, const std::shared_ptr<Scope>& scope = nullptr);
|
|
109
|
+
|
|
110
|
+
/// Open subscriptions (for debug ownership reports and tests).
|
|
111
|
+
size_t subscriptions() const;
|
|
112
|
+
|
|
113
|
+
private:
|
|
114
|
+
std::shared_ptr<Resource> add(std::shared_ptr<detail::LifecycleListener> listener, const std::shared_ptr<Scope>& scope);
|
|
115
|
+
|
|
116
|
+
const std::shared_ptr<detail::LifecycleState> state_;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/// The scene to present from, of `scenes` (most recently activated first):
|
|
120
|
+
/// the first in the foreground and active, else the first in the
|
|
121
|
+
/// foreground; none while every scene is in the background or unattached.
|
|
122
|
+
std::optional<SceneId> presentingScene(const std::vector<SceneId>& scenes, const std::function<SceneState(SceneId)>& stateOf);
|
|
123
|
+
|
|
124
|
+
} // namespace lucent
|
|
@@ -4,11 +4,16 @@
|
|
|
4
4
|
#include "abort.h"
|
|
5
5
|
#include "array.h"
|
|
6
6
|
#include "async.h"
|
|
7
|
+
#include "bigint.h"
|
|
8
|
+
#include "buffer.h"
|
|
7
9
|
#include "bytes.h"
|
|
10
|
+
#include "callback.h"
|
|
8
11
|
#include "console.h"
|
|
12
|
+
#include "conversions.h"
|
|
9
13
|
#include "core.h"
|
|
10
14
|
#include "date.h"
|
|
11
15
|
#include "equality.h"
|
|
16
|
+
#include "extension.h"
|
|
12
17
|
#include "jserror.h"
|
|
13
18
|
#include "function.h"
|
|
14
19
|
#include "generator.h"
|
|
@@ -19,6 +24,8 @@
|
|
|
19
24
|
#include "native.h"
|
|
20
25
|
#include "number.h"
|
|
21
26
|
#include "regexp.h"
|
|
27
|
+
#include "report.h"
|
|
28
|
+
#include "resource.h"
|
|
22
29
|
#include "ops.h"
|
|
23
30
|
#include "scheduler.h"
|
|
24
31
|
#include "jsstring.h"
|
package/runtime/cpp/lucent/map.h
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
#include <vector>
|
|
11
11
|
|
|
12
12
|
#include "array.h"
|
|
13
|
+
#include "bigint.h"
|
|
13
14
|
#include "core.h"
|
|
14
15
|
#include "equality.h"
|
|
15
16
|
|
|
@@ -28,10 +29,16 @@ struct KeyHash {
|
|
|
28
29
|
return std::hash<uint64_t>()(bits);
|
|
29
30
|
} else if constexpr (std::is_same_v<K, bool>) {
|
|
30
31
|
return k ? 1 : 2;
|
|
31
|
-
} else if constexpr (std::is_same_v<K, String>) {
|
|
32
|
+
} else if constexpr (std::is_same_v<K, String> || std::is_same_v<K, BigInt>) {
|
|
32
33
|
return k.hash();
|
|
33
34
|
} else if constexpr (IsRef<K>::value) {
|
|
34
35
|
return std::hash<const void*>()(static_cast<const void*>(k.get()));
|
|
36
|
+
} else if constexpr (IsOpt<K>::value) {
|
|
37
|
+
if (!k.has()) return k.isNull() ? 3 : 4;
|
|
38
|
+
return KeyHash<std::decay_t<decltype(k.get())>>()(k.get());
|
|
39
|
+
} else if constexpr (IsVariant<K>::value) {
|
|
40
|
+
// Equal members hash alike whichever alternative holds them.
|
|
41
|
+
return std::visit([](const auto& x) { return KeyHash<std::decay_t<decltype(x)>>()(x); }, k);
|
|
35
42
|
} else {
|
|
36
43
|
return std::hash<const void*>()(k.identity());
|
|
37
44
|
}
|
|
@@ -224,13 +231,22 @@ class Map {
|
|
|
224
231
|
|
|
225
232
|
Table& table() const { return *t_; }
|
|
226
233
|
const void* identity() const { return t_.get(); }
|
|
227
|
-
friend bool strictEquals(const Map& a, const Map& b) { return a.t_ == b.t_; }
|
|
228
|
-
friend String toJsString(const Map&) { return String::fromLatin1("[object Map]"); }
|
|
229
234
|
|
|
230
235
|
private:
|
|
231
236
|
std::shared_ptr<Table> t_;
|
|
232
237
|
};
|
|
233
238
|
|
|
239
|
+
template <class K, class V>
|
|
240
|
+
String toJsString(const Map<K, V>&) {
|
|
241
|
+
return String::fromLatin1("[object Map]");
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/// `===`: the same map.
|
|
245
|
+
template <class K, class V>
|
|
246
|
+
bool strictEquals(const Map<K, V>& a, const Map<K, V>& b) {
|
|
247
|
+
return a.identity() == b.identity();
|
|
248
|
+
}
|
|
249
|
+
|
|
234
250
|
template <class T>
|
|
235
251
|
class Set {
|
|
236
252
|
public:
|
|
@@ -268,13 +284,22 @@ class Set {
|
|
|
268
284
|
|
|
269
285
|
Table& table() const { return *t_; }
|
|
270
286
|
const void* identity() const { return t_.get(); }
|
|
271
|
-
friend bool strictEquals(const Set& a, const Set& b) { return a.t_ == b.t_; }
|
|
272
|
-
friend String toJsString(const Set&) { return String::fromLatin1("[object Set]"); }
|
|
273
287
|
|
|
274
288
|
private:
|
|
275
289
|
std::shared_ptr<Table> t_;
|
|
276
290
|
};
|
|
277
291
|
|
|
292
|
+
template <class T>
|
|
293
|
+
String toJsString(const Set<T>&) {
|
|
294
|
+
return String::fromLatin1("[object Set]");
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/// `===`: the same set.
|
|
298
|
+
template <class T>
|
|
299
|
+
bool strictEquals(const Set<T>& a, const Set<T>& b) {
|
|
300
|
+
return a.identity() == b.identity();
|
|
301
|
+
}
|
|
302
|
+
|
|
278
303
|
/// `Record<string, V>` / `{ [key: string]: V }`: a plain object used as a
|
|
279
304
|
/// dictionary.
|
|
280
305
|
template <class V>
|
|
@@ -319,8 +344,6 @@ class Dict {
|
|
|
319
344
|
|
|
320
345
|
Table& table() const { return *t_; }
|
|
321
346
|
const void* identity() const { return t_.get(); }
|
|
322
|
-
friend bool strictEquals(const Dict& a, const Dict& b) { return a.t_ == b.t_; }
|
|
323
|
-
friend String toJsString(const Dict&) { return String::fromLatin1("[object Object]"); }
|
|
324
347
|
|
|
325
348
|
static bool isArrayIndex(const String& k, double& out) {
|
|
326
349
|
size_t n = k.length();
|
|
@@ -341,4 +364,15 @@ class Dict {
|
|
|
341
364
|
std::shared_ptr<Table> t_;
|
|
342
365
|
};
|
|
343
366
|
|
|
367
|
+
template <class V>
|
|
368
|
+
String toJsString(const Dict<V>&) {
|
|
369
|
+
return String::fromLatin1("[object Object]");
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/// `===`: the same record.
|
|
373
|
+
template <class V>
|
|
374
|
+
bool strictEquals(const Dict<V>& a, const Dict<V>& b) {
|
|
375
|
+
return a.identity() == b.identity();
|
|
376
|
+
}
|
|
377
|
+
|
|
344
378
|
} // namespace lucent
|
|
@@ -11,65 +11,53 @@
|
|
|
11
11
|
namespace lucent {
|
|
12
12
|
namespace {
|
|
13
13
|
std::atomic<long> nativeRefs{0};
|
|
14
|
-
}
|
|
14
|
+
std::atomic<long> moduleRefs{0};
|
|
15
|
+
} // namespace
|
|
16
|
+
|
|
15
17
|
long liveNativeRefs() { return nativeRefs.load(); }
|
|
16
|
-
|
|
18
|
+
|
|
19
|
+
long moduleNativeRefs() { return moduleRefs.load(); }
|
|
20
|
+
|
|
21
|
+
bool detail::countNativeRef() {
|
|
22
|
+
nativeRefs++;
|
|
23
|
+
|
|
24
|
+
// Made in the main context: a view's, which the renderer releases with it.
|
|
25
|
+
if (ExecutionContext::current() == &ExecutionContext::main()) return false;
|
|
26
|
+
|
|
27
|
+
moduleRefs++;
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
void detail::uncountNativeRef(bool module, bool held) {
|
|
32
|
+
if (module) moduleRefs--;
|
|
33
|
+
if (!held) nativeRefs--;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
void detail::releaseNative(void* handle, void (*release)(void*), ExecutionContext* on, bool module) {
|
|
37
|
+
detail::runOn(on, [handle, release, module] {
|
|
38
|
+
release(handle);
|
|
39
|
+
uncountNativeRef(module);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
17
42
|
} // namespace lucent
|
|
18
43
|
|
|
19
44
|
#if !defined(__ANDROID__) && !(defined(TARGET_OS_IOS) && TARGET_OS_IOS)
|
|
20
45
|
|
|
21
|
-
#include <condition_variable>
|
|
22
|
-
#include <deque>
|
|
23
|
-
#include <mutex>
|
|
24
|
-
#include <thread>
|
|
25
|
-
|
|
26
46
|
namespace lucent {
|
|
27
47
|
|
|
28
48
|
namespace {
|
|
29
49
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
static
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
void post(std::function<void()> job) {
|
|
37
|
-
{
|
|
38
|
-
std::lock_guard<std::mutex> g(m_);
|
|
39
|
-
jobs_.push_back(std::move(job));
|
|
40
|
-
}
|
|
41
|
-
cv_.notify_one();
|
|
42
|
-
}
|
|
43
|
-
bool current() const { return std::this_thread::get_id() == id_; }
|
|
44
|
-
|
|
45
|
-
private:
|
|
46
|
-
HostMainThread() {
|
|
47
|
-
std::thread t([this] { run(); });
|
|
48
|
-
id_ = t.get_id();
|
|
49
|
-
t.detach();
|
|
50
|
-
}
|
|
51
|
-
void run() {
|
|
52
|
-
for (;;) {
|
|
53
|
-
std::function<void()> job;
|
|
54
|
-
{
|
|
55
|
-
std::unique_lock<std::mutex> g(m_);
|
|
56
|
-
cv_.wait(g, [this] { return !jobs_.empty(); });
|
|
57
|
-
job = std::move(jobs_.front());
|
|
58
|
-
jobs_.pop_front();
|
|
59
|
-
}
|
|
60
|
-
job();
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
std::mutex m_;
|
|
64
|
-
std::condition_variable cv_;
|
|
65
|
-
std::deque<std::function<void()>> jobs_;
|
|
66
|
-
std::thread::id id_;
|
|
67
|
-
};
|
|
50
|
+
/// The host's stand-in for the platform's main thread: lives for the process.
|
|
51
|
+
WorkerThread& hostMainThread() {
|
|
52
|
+
static auto* thread = new std::shared_ptr<WorkerThread>(WorkerThread::start([](Job& job) { detail::runGuarded(job, "job"); }));
|
|
53
|
+
return **thread;
|
|
54
|
+
}
|
|
68
55
|
|
|
69
56
|
} // namespace
|
|
70
57
|
|
|
71
|
-
void postToMain(std::function<void()> job) {
|
|
72
|
-
|
|
58
|
+
void postToMain(std::function<void()> job) { hostMainThread().post(std::move(job)); }
|
|
59
|
+
|
|
60
|
+
bool onMainThread() { return hostMainThread().isCurrent(); }
|
|
73
61
|
|
|
74
62
|
} // namespace lucent
|
|
75
63
|
|