@effindomv2/fui-rs 0.1.3
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/COMMERCIAL.md +7 -0
- package/Cargo.toml +34 -0
- package/LICENSE.md +9 -0
- package/README.md +88 -0
- package/package.json +54 -0
- package/scripts/build.sh +227 -0
- package/scripts/check-runtime-dependency.sh +41 -0
- package/scripts/framework-host-services.ts +40 -0
- package/scripts/generate-host-events.ts +17 -0
- package/scripts/generate-host-services.ts +28 -0
- package/scripts/hostgen/common.ts +73 -0
- package/scripts/hostgen/registry.ts +159 -0
- package/scripts/hostgen/rust-host-events.ts +171 -0
- package/scripts/hostgen/rust-host-services.ts +257 -0
- package/src/animation.rs +625 -0
- package/src/app.rs +324 -0
- package/src/assets.rs +572 -0
- package/src/bindings/mod.rs +1 -0
- package/src/bindings/ui.rs +705 -0
- package/src/bitmap.rs +317 -0
- package/src/bridge_callbacks.rs +242 -0
- package/src/context_menu_manager.rs +332 -0
- package/src/controls/anti_selection_area.rs +54 -0
- package/src/controls/button.rs +542 -0
- package/src/controls/checkbox.rs +372 -0
- package/src/controls/combobox.rs +1574 -0
- package/src/controls/context_menu.rs +1367 -0
- package/src/controls/control_template_set.rs +46 -0
- package/src/controls/control_tokens.rs +596 -0
- package/src/controls/dialog.rs +590 -0
- package/src/controls/dropdown.rs +1010 -0
- package/src/controls/form.rs +229 -0
- package/src/controls/internal/button_presenter.rs +142 -0
- package/src/controls/internal/checkbox_indicator_presenter.rs +210 -0
- package/src/controls/internal/dropdown_chevron_presenter.rs +134 -0
- package/src/controls/internal/dropdown_field_presenter.rs +269 -0
- package/src/controls/internal/dropdown_option_row_presenter.rs +184 -0
- package/src/controls/internal/mod.rs +13 -0
- package/src/controls/internal/pressable_indicator_presenter.rs +26 -0
- package/src/controls/internal/pressable_labeled_control.rs +492 -0
- package/src/controls/internal/radio_indicator_presenter.rs +208 -0
- package/src/controls/internal/selectable_popup_list.rs +597 -0
- package/src/controls/internal/slider_presenter.rs +282 -0
- package/src/controls/internal/switch_indicator_presenter.rs +235 -0
- package/src/controls/internal/text_input_core.rs +1074 -0
- package/src/controls/internal/text_input_presenter.rs +108 -0
- package/src/controls/mod.rs +235 -0
- package/src/controls/nav_link.rs +395 -0
- package/src/controls/popup.rs +191 -0
- package/src/controls/progress_bar.rs +287 -0
- package/src/controls/radio_button.rs +348 -0
- package/src/controls/radio_group.rs +283 -0
- package/src/controls/selection_area.rs +82 -0
- package/src/controls/shared.rs +68 -0
- package/src/controls/slider.rs +701 -0
- package/src/controls/switch.rs +293 -0
- package/src/controls/templating.rs +49 -0
- package/src/controls/tests.rs +3905 -0
- package/src/controls/text_area.rs +207 -0
- package/src/controls/text_input.rs +192 -0
- package/src/debug.rs +146 -0
- package/src/drag_drop.rs +424 -0
- package/src/drag_gesture.rs +258 -0
- package/src/drawing.rs +385 -0
- package/src/event.rs +1603 -0
- package/src/external_drop.rs +467 -0
- package/src/fetch.rs +500 -0
- package/src/ffi.rs +3542 -0
- package/src/file.rs +1677 -0
- package/src/focus_adorner.rs +307 -0
- package/src/focus_visibility.rs +121 -0
- package/src/frame_scheduler.rs +159 -0
- package/src/frame_signal.rs +64 -0
- package/src/generated/ffi.rs +798 -0
- package/src/generated/framework_host_services.rs +74 -0
- package/src/generated/mod.rs +2 -0
- package/src/host_services.rs +162 -0
- package/src/image_sampling.rs +78 -0
- package/src/keyboard_scroll.rs +137 -0
- package/src/keyboard_scroll_tracker.rs +385 -0
- package/src/lib.rs +547 -0
- package/src/logger.rs +56 -0
- package/src/mobile_text_selection_toolbar.rs +1034 -0
- package/src/navigation.rs +48 -0
- package/src/node/core.rs +2210 -0
- package/src/node/custom_drawable.rs +149 -0
- package/src/node/flex_box.rs +874 -0
- package/src/node/grid.rs +304 -0
- package/src/node/helpers.rs +442 -0
- package/src/node/image.rs +506 -0
- package/src/node/mod.rs +315 -0
- package/src/node/scroll_bar.rs +845 -0
- package/src/node/scroll_box.rs +514 -0
- package/src/node/scroll_state.rs +121 -0
- package/src/node/scroll_view.rs +557 -0
- package/src/node/svg_node.rs +474 -0
- package/src/node/text_node.rs +633 -0
- package/src/node/virtual_list.rs +678 -0
- package/src/panic_hook.rs +36 -0
- package/src/persisted.rs +274 -0
- package/src/platform.rs +556 -0
- package/src/popup_presenter.rs +344 -0
- package/src/selection_handle_adorner.rs +838 -0
- package/src/signal.rs +134 -0
- package/src/text.rs +1065 -0
- package/src/theme.rs +571 -0
- package/src/timers.rs +106 -0
- package/src/tool_tip.rs +167 -0
- package/src/tool_tip_manager.rs +691 -0
- package/src/transitions.rs +41 -0
- package/src/typography.rs +520 -0
- package/src/viewport.rs +108 -0
- package/src/worker.rs +308 -0
- package/src/worker_job.rs +82 -0
- package/src/worker_runtime.rs +172 -0
package/src/worker.rs
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
use std::cell::RefCell;
|
|
2
|
+
use std::collections::HashMap;
|
|
3
|
+
use std::rc::Rc;
|
|
4
|
+
|
|
5
|
+
use crate::ffi;
|
|
6
|
+
|
|
7
|
+
type ProgressCallback = Rc<dyn Fn(WorkerProgressEventArgs)>;
|
|
8
|
+
type CompleteCallback = Rc<dyn Fn(WorkerCompletedEventArgs)>;
|
|
9
|
+
type ErrorCallback = Rc<dyn Fn(WorkerErrorEventArgs)>;
|
|
10
|
+
const MAX_WORKER_START_INPUT_BYTES: usize = 1024 * 1024;
|
|
11
|
+
|
|
12
|
+
thread_local! {
|
|
13
|
+
static NEXT_WORKER_ID: RefCell<u32> = const { RefCell::new(1) };
|
|
14
|
+
static ACTIVE_WORKERS: RefCell<HashMap<u32, Rc<RefCell<WorkerInner>>>> = RefCell::new(HashMap::new());
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fn with_utf8(value: &str, callback: impl FnOnce(usize, u32)) {
|
|
18
|
+
let bytes = value.as_bytes();
|
|
19
|
+
callback(
|
|
20
|
+
if bytes.is_empty() {
|
|
21
|
+
0
|
|
22
|
+
} else {
|
|
23
|
+
bytes.as_ptr() as usize
|
|
24
|
+
},
|
|
25
|
+
bytes.len() as u32,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
30
|
+
pub struct WorkerProgressEventArgs {
|
|
31
|
+
pub message: String,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
35
|
+
pub struct WorkerCompletedEventArgs {
|
|
36
|
+
pub result: String,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
40
|
+
pub struct WorkerErrorEventArgs {
|
|
41
|
+
pub message: String,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
struct WorkerInner {
|
|
45
|
+
worker_id: u32,
|
|
46
|
+
wasm_path: String,
|
|
47
|
+
entry_name: String,
|
|
48
|
+
on_progress: Option<ProgressCallback>,
|
|
49
|
+
on_complete: Option<CompleteCallback>,
|
|
50
|
+
on_error: Option<ErrorCallback>,
|
|
51
|
+
started: bool,
|
|
52
|
+
finished: bool,
|
|
53
|
+
cancel_requested: bool,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
pub struct Worker {
|
|
57
|
+
inner: Rc<RefCell<WorkerInner>>,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
impl Worker {
|
|
61
|
+
pub fn new(wasm_path: impl Into<String>, entry_name: impl Into<String>) -> Self {
|
|
62
|
+
let worker_id = NEXT_WORKER_ID.with(|next| {
|
|
63
|
+
let mut slot = next.borrow_mut();
|
|
64
|
+
let id = *slot;
|
|
65
|
+
*slot += 1;
|
|
66
|
+
id
|
|
67
|
+
});
|
|
68
|
+
let worker = Self {
|
|
69
|
+
inner: Rc::new(RefCell::new(WorkerInner {
|
|
70
|
+
worker_id,
|
|
71
|
+
wasm_path: wasm_path.into(),
|
|
72
|
+
entry_name: entry_name.into(),
|
|
73
|
+
on_progress: None,
|
|
74
|
+
on_complete: None,
|
|
75
|
+
on_error: None,
|
|
76
|
+
started: false,
|
|
77
|
+
finished: false,
|
|
78
|
+
cancel_requested: false,
|
|
79
|
+
})),
|
|
80
|
+
};
|
|
81
|
+
ACTIVE_WORKERS.with(|workers| {
|
|
82
|
+
workers.borrow_mut().insert(worker_id, worker.inner.clone());
|
|
83
|
+
});
|
|
84
|
+
worker
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
pub fn on_progress(self, handler: impl Fn(WorkerProgressEventArgs) + 'static) -> Self {
|
|
88
|
+
self.inner.borrow_mut().on_progress = Some(Rc::new(handler));
|
|
89
|
+
self
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
pub fn on_complete(self, handler: impl Fn(WorkerCompletedEventArgs) + 'static) -> Self {
|
|
93
|
+
self.inner.borrow_mut().on_complete = Some(Rc::new(handler));
|
|
94
|
+
self
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
pub fn on_error(self, handler: impl Fn(WorkerErrorEventArgs) + 'static) -> Self {
|
|
98
|
+
self.inner.borrow_mut().on_error = Some(Rc::new(handler));
|
|
99
|
+
self
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
pub fn start(self, input: impl Into<String>) -> Self {
|
|
103
|
+
let input = input.into();
|
|
104
|
+
let already_started = {
|
|
105
|
+
let inner = self.inner.borrow();
|
|
106
|
+
inner.started || inner.finished
|
|
107
|
+
};
|
|
108
|
+
if already_started {
|
|
109
|
+
return self;
|
|
110
|
+
}
|
|
111
|
+
if input.as_bytes().len() > MAX_WORKER_START_INPUT_BYTES {
|
|
112
|
+
let (worker_id, callback) = {
|
|
113
|
+
let mut inner = self.inner.borrow_mut();
|
|
114
|
+
inner.started = true;
|
|
115
|
+
inner.finished = true;
|
|
116
|
+
(inner.worker_id, inner.on_error.clone())
|
|
117
|
+
};
|
|
118
|
+
finish_worker(worker_id);
|
|
119
|
+
if let Some(callback) = callback {
|
|
120
|
+
callback(WorkerErrorEventArgs {
|
|
121
|
+
message: format!(
|
|
122
|
+
"Worker.start input exceeds the maximum UTF-8 payload size of {} bytes.",
|
|
123
|
+
MAX_WORKER_START_INPUT_BYTES
|
|
124
|
+
),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return self;
|
|
128
|
+
}
|
|
129
|
+
let start_info = {
|
|
130
|
+
let mut inner = self.inner.borrow_mut();
|
|
131
|
+
inner.started = true;
|
|
132
|
+
(
|
|
133
|
+
inner.worker_id,
|
|
134
|
+
inner.wasm_path.clone(),
|
|
135
|
+
inner.entry_name.clone(),
|
|
136
|
+
)
|
|
137
|
+
};
|
|
138
|
+
with_utf8(&start_info.1, |wasm_path_ptr, wasm_path_len| {
|
|
139
|
+
with_utf8(&start_info.2, |entry_ptr, entry_len| {
|
|
140
|
+
with_utf8(&input, |input_ptr, input_len| unsafe {
|
|
141
|
+
ffi::fui_worker_start_string(
|
|
142
|
+
start_info.0,
|
|
143
|
+
wasm_path_ptr,
|
|
144
|
+
wasm_path_len,
|
|
145
|
+
entry_ptr,
|
|
146
|
+
entry_len,
|
|
147
|
+
input_ptr,
|
|
148
|
+
input_len,
|
|
149
|
+
);
|
|
150
|
+
})
|
|
151
|
+
})
|
|
152
|
+
});
|
|
153
|
+
self
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
pub fn cancel(&self) {
|
|
157
|
+
let worker_id = {
|
|
158
|
+
let mut inner = self.inner.borrow_mut();
|
|
159
|
+
if !inner.started || inner.finished || inner.cancel_requested {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
inner.cancel_requested = true;
|
|
163
|
+
inner.worker_id
|
|
164
|
+
};
|
|
165
|
+
unsafe { ffi::fui_worker_cancel(worker_id) };
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
impl Drop for Worker {
|
|
170
|
+
fn drop(&mut self) {
|
|
171
|
+
self.cancel();
|
|
172
|
+
finish_worker(self.inner.borrow().worker_id);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
fn finish_worker(worker_id: u32) -> Option<Rc<RefCell<WorkerInner>>> {
|
|
177
|
+
ACTIVE_WORKERS.with(|workers| workers.borrow_mut().remove(&worker_id))
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
fn with_active_worker(worker_id: u32, callback: impl FnOnce(&mut WorkerInner)) {
|
|
181
|
+
let Some(worker) = ACTIVE_WORKERS.with(|workers| workers.borrow().get(&worker_id).cloned())
|
|
182
|
+
else {
|
|
183
|
+
return;
|
|
184
|
+
};
|
|
185
|
+
let mut inner = worker.borrow_mut();
|
|
186
|
+
callback(&mut inner);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
#[no_mangle]
|
|
190
|
+
pub extern "C" fn __fui_on_worker_progress(worker_id: u32, text_ptr: *const u8, text_len: u32) {
|
|
191
|
+
let message = if text_ptr.is_null() || text_len == 0 {
|
|
192
|
+
String::new()
|
|
193
|
+
} else {
|
|
194
|
+
String::from_utf8_lossy(unsafe { std::slice::from_raw_parts(text_ptr, text_len as usize) })
|
|
195
|
+
.into_owned()
|
|
196
|
+
};
|
|
197
|
+
with_active_worker(worker_id, |inner| {
|
|
198
|
+
if inner.finished || inner.cancel_requested {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if let Some(callback) = inner.on_progress.clone() {
|
|
202
|
+
callback(WorkerProgressEventArgs { message });
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
#[no_mangle]
|
|
208
|
+
pub extern "C" fn __fui_on_worker_complete(worker_id: u32, text_ptr: *const u8, text_len: u32) {
|
|
209
|
+
let result = if text_ptr.is_null() || text_len == 0 {
|
|
210
|
+
String::new()
|
|
211
|
+
} else {
|
|
212
|
+
String::from_utf8_lossy(unsafe { std::slice::from_raw_parts(text_ptr, text_len as usize) })
|
|
213
|
+
.into_owned()
|
|
214
|
+
};
|
|
215
|
+
let Some(worker) = finish_worker(worker_id) else {
|
|
216
|
+
return;
|
|
217
|
+
};
|
|
218
|
+
let callback = {
|
|
219
|
+
let mut inner = worker.borrow_mut();
|
|
220
|
+
if inner.finished {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
inner.finished = true;
|
|
224
|
+
inner.on_complete.clone()
|
|
225
|
+
};
|
|
226
|
+
if let Some(callback) = callback {
|
|
227
|
+
callback(WorkerCompletedEventArgs { result });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
#[no_mangle]
|
|
232
|
+
pub extern "C" fn __fui_on_worker_error(worker_id: u32, text_ptr: *const u8, text_len: u32) {
|
|
233
|
+
let message = if text_ptr.is_null() || text_len == 0 {
|
|
234
|
+
String::new()
|
|
235
|
+
} else {
|
|
236
|
+
String::from_utf8_lossy(unsafe { std::slice::from_raw_parts(text_ptr, text_len as usize) })
|
|
237
|
+
.into_owned()
|
|
238
|
+
};
|
|
239
|
+
let Some(worker) = finish_worker(worker_id) else {
|
|
240
|
+
return;
|
|
241
|
+
};
|
|
242
|
+
let callback = {
|
|
243
|
+
let mut inner = worker.borrow_mut();
|
|
244
|
+
if inner.finished {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
inner.finished = true;
|
|
248
|
+
inner.on_error.clone()
|
|
249
|
+
};
|
|
250
|
+
if let Some(callback) = callback {
|
|
251
|
+
callback(WorkerErrorEventArgs { message });
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
#[cfg(test)]
|
|
256
|
+
mod tests {
|
|
257
|
+
use super::Worker;
|
|
258
|
+
use crate::ffi::{self, Call};
|
|
259
|
+
use std::cell::RefCell;
|
|
260
|
+
use std::rc::Rc;
|
|
261
|
+
|
|
262
|
+
#[test]
|
|
263
|
+
fn worker_start_emits_host_call() {
|
|
264
|
+
ffi::test::reset();
|
|
265
|
+
let _worker = Worker::new("./workers/test.wasm", "demo").start("hello");
|
|
266
|
+
let calls = ffi::test::take_calls();
|
|
267
|
+
assert!(calls.iter().any(|call| matches!(call, Call::WorkerStartString { wasm_path, entry, input, .. } if wasm_path == "./workers/test.wasm" && entry == "demo" && input == "hello")));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
#[test]
|
|
271
|
+
fn oversized_worker_start_input_reports_error_without_host_call() {
|
|
272
|
+
ffi::test::reset();
|
|
273
|
+
let error = Rc::new(RefCell::new(String::new()));
|
|
274
|
+
let error_clone = error.clone();
|
|
275
|
+
let input = "x".repeat(super::MAX_WORKER_START_INPUT_BYTES + 1);
|
|
276
|
+
let _worker = Worker::new("./workers/test.wasm", "demo")
|
|
277
|
+
.on_error(move |event| {
|
|
278
|
+
error_clone.replace(event.message);
|
|
279
|
+
})
|
|
280
|
+
.start(input);
|
|
281
|
+
let calls = ffi::test::take_calls();
|
|
282
|
+
assert!(!calls
|
|
283
|
+
.iter()
|
|
284
|
+
.any(|call| matches!(call, Call::WorkerStartString { .. })));
|
|
285
|
+
assert!(error.borrow().contains("maximum UTF-8 payload size"));
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
#[test]
|
|
289
|
+
fn worker_callbacks_receive_payloads() {
|
|
290
|
+
ffi::test::reset();
|
|
291
|
+
let progress = Rc::new(RefCell::new(String::new()));
|
|
292
|
+
let result = Rc::new(RefCell::new(String::new()));
|
|
293
|
+
let progress_clone = progress.clone();
|
|
294
|
+
let result_clone = result.clone();
|
|
295
|
+
let _worker = Worker::new("./workers/test.wasm", "demo")
|
|
296
|
+
.on_progress(move |event| {
|
|
297
|
+
progress_clone.replace(event.message);
|
|
298
|
+
})
|
|
299
|
+
.on_complete(move |event| {
|
|
300
|
+
result_clone.replace(event.result);
|
|
301
|
+
})
|
|
302
|
+
.start("hello");
|
|
303
|
+
super::__fui_on_worker_progress(1, b"25%".as_ptr(), 3);
|
|
304
|
+
super::__fui_on_worker_complete(1, b"done".as_ptr(), 4);
|
|
305
|
+
assert_eq!(&*progress.borrow(), "25%");
|
|
306
|
+
assert_eq!(&*result.borrow(), "done");
|
|
307
|
+
}
|
|
308
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
use crate::worker_runtime::WorkerRuntime;
|
|
2
|
+
|
|
3
|
+
#[derive(Default)]
|
|
4
|
+
pub struct WorkerJobState {
|
|
5
|
+
started: bool,
|
|
6
|
+
finished: bool,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
impl WorkerJobState {
|
|
10
|
+
pub const fn new() -> Self {
|
|
11
|
+
Self {
|
|
12
|
+
started: false,
|
|
13
|
+
finished: false,
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
pub trait WorkerJob {
|
|
19
|
+
fn state(&mut self) -> &mut WorkerJobState;
|
|
20
|
+
|
|
21
|
+
fn on_start(&mut self, _input: String) {}
|
|
22
|
+
|
|
23
|
+
fn run(&mut self);
|
|
24
|
+
|
|
25
|
+
fn resume(&mut self, input: String) -> bool {
|
|
26
|
+
let should_start = {
|
|
27
|
+
let state = self.state();
|
|
28
|
+
if state.started {
|
|
29
|
+
false
|
|
30
|
+
} else {
|
|
31
|
+
state.started = true;
|
|
32
|
+
true
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
if should_start {
|
|
36
|
+
self.on_start(input);
|
|
37
|
+
}
|
|
38
|
+
if self.state().finished {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
self.run();
|
|
42
|
+
!self.state().finished
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
fn report_progress(&mut self, progress: impl AsRef<str>) {
|
|
46
|
+
if self.state().finished {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
WorkerRuntime::report_progress(progress);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fn complete(&mut self, result: impl AsRef<str>) {
|
|
53
|
+
if self.state().finished {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
self.state().finished = true;
|
|
57
|
+
WorkerRuntime::complete(result);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
fn fail(&mut self, message: impl AsRef<str>) {
|
|
61
|
+
if self.state().finished {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
self.state().finished = true;
|
|
65
|
+
WorkerRuntime::fail(message);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
fn is_cancelled(&self) -> bool {
|
|
69
|
+
WorkerRuntime::is_cancelled()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fn r#yield(&mut self, delay_ms: i32) -> bool {
|
|
73
|
+
if self.state().finished {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
WorkerRuntime::r#yield(delay_ms)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fn yield_now(&mut self, delay_ms: i32) -> bool {
|
|
80
|
+
self.r#yield(delay_ms)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
use std::cell::{Cell, RefCell};
|
|
2
|
+
thread_local! {
|
|
3
|
+
static WORKER_TERMINAL_SENT: Cell<bool> = const { Cell::new(false) };
|
|
4
|
+
static WORKER_CALLBACK_BUFFER: RefCell<Box<[u8]>> =
|
|
5
|
+
RefCell::new(vec![0u8; 1024 * 1024].into_boxed_slice());
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
#[cfg(target_arch = "wasm32")]
|
|
9
|
+
#[link(wasm_import_module = "fui_worker_host")]
|
|
10
|
+
unsafe extern "C" {
|
|
11
|
+
#[link_name = "fui_worker_report_progress"]
|
|
12
|
+
fn host_worker_report_progress(ptr: usize, len: u32);
|
|
13
|
+
#[link_name = "fui_worker_complete_string"]
|
|
14
|
+
fn host_worker_complete_string(ptr: usize, len: u32);
|
|
15
|
+
#[link_name = "fui_worker_fail"]
|
|
16
|
+
fn host_worker_fail(ptr: usize, len: u32);
|
|
17
|
+
#[link_name = "fui_worker_is_cancelled"]
|
|
18
|
+
fn host_worker_is_cancelled() -> bool;
|
|
19
|
+
#[link_name = "fui_worker_request_yield"]
|
|
20
|
+
fn host_worker_request_yield();
|
|
21
|
+
#[link_name = "fui_worker_request_yield_delay"]
|
|
22
|
+
fn host_worker_request_yield_delay(delay_ms: i32);
|
|
23
|
+
#[link_name = "fui_file_read_chunk"]
|
|
24
|
+
fn host_file_read_chunk(offset_low: i32, offset_high: i32, max_bytes: i32) -> i32;
|
|
25
|
+
#[link_name = "fui_file_worker_write_chunk"]
|
|
26
|
+
fn host_file_worker_write_chunk(ptr: usize, len: i32);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#[cfg(target_arch = "wasm32")]
|
|
30
|
+
fn with_utf8(value: &str, callback: impl FnOnce(usize, u32)) {
|
|
31
|
+
let bytes = value.as_bytes();
|
|
32
|
+
callback(
|
|
33
|
+
if bytes.is_empty() {
|
|
34
|
+
0
|
|
35
|
+
} else {
|
|
36
|
+
bytes.as_ptr() as usize
|
|
37
|
+
},
|
|
38
|
+
bytes.len() as u32,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
pub struct WorkerRuntime;
|
|
43
|
+
|
|
44
|
+
impl WorkerRuntime {
|
|
45
|
+
pub fn entry_input(input_ptr: usize, input_len: u32) -> String {
|
|
46
|
+
if input_ptr == 0 || input_len == 0 {
|
|
47
|
+
return String::new();
|
|
48
|
+
}
|
|
49
|
+
let bytes =
|
|
50
|
+
unsafe { std::slice::from_raw_parts(input_ptr as *const u8, input_len as usize) };
|
|
51
|
+
String::from_utf8_lossy(bytes).into_owned()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
pub fn report_progress(progress: impl AsRef<str>) {
|
|
55
|
+
if WORKER_TERMINAL_SENT.with(Cell::get) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
#[cfg(target_arch = "wasm32")]
|
|
59
|
+
send_text(progress.as_ref(), |ptr, len| unsafe {
|
|
60
|
+
host_worker_report_progress(ptr, len);
|
|
61
|
+
});
|
|
62
|
+
#[cfg(not(target_arch = "wasm32"))]
|
|
63
|
+
let _ = progress.as_ref();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
pub fn complete(result: impl AsRef<str>) {
|
|
67
|
+
if WORKER_TERMINAL_SENT.with(Cell::get) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
WORKER_TERMINAL_SENT.with(|sent| sent.set(true));
|
|
71
|
+
#[cfg(target_arch = "wasm32")]
|
|
72
|
+
send_text(result.as_ref(), |ptr, len| unsafe {
|
|
73
|
+
host_worker_complete_string(ptr, len);
|
|
74
|
+
});
|
|
75
|
+
#[cfg(not(target_arch = "wasm32"))]
|
|
76
|
+
let _ = result.as_ref();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
pub fn fail(message: impl AsRef<str>) {
|
|
80
|
+
if WORKER_TERMINAL_SENT.with(Cell::get) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
WORKER_TERMINAL_SENT.with(|sent| sent.set(true));
|
|
84
|
+
#[cfg(target_arch = "wasm32")]
|
|
85
|
+
send_text(message.as_ref(), |ptr, len| unsafe {
|
|
86
|
+
host_worker_fail(ptr, len);
|
|
87
|
+
});
|
|
88
|
+
#[cfg(not(target_arch = "wasm32"))]
|
|
89
|
+
let _ = message.as_ref();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
pub fn is_cancelled() -> bool {
|
|
93
|
+
#[cfg(target_arch = "wasm32")]
|
|
94
|
+
{
|
|
95
|
+
unsafe { host_worker_is_cancelled() }
|
|
96
|
+
}
|
|
97
|
+
#[cfg(not(target_arch = "wasm32"))]
|
|
98
|
+
{
|
|
99
|
+
false
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
pub fn r#yield(delay_ms: i32) -> bool {
|
|
104
|
+
if WORKER_TERMINAL_SENT.with(Cell::get) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
#[cfg(target_arch = "wasm32")]
|
|
108
|
+
unsafe {
|
|
109
|
+
if delay_ms > 0 {
|
|
110
|
+
host_worker_request_yield_delay(delay_ms);
|
|
111
|
+
} else {
|
|
112
|
+
host_worker_request_yield();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
#[cfg(not(target_arch = "wasm32"))]
|
|
116
|
+
let _ = delay_ms;
|
|
117
|
+
true
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
pub fn yield_now(delay_ms: i32) -> bool {
|
|
121
|
+
Self::r#yield(delay_ms)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
pub fn file_read_chunk(offset_low: i32, offset_high: i32, max_bytes: i32) -> i32 {
|
|
126
|
+
#[cfg(target_arch = "wasm32")]
|
|
127
|
+
{
|
|
128
|
+
unsafe { host_file_read_chunk(offset_low, offset_high, max_bytes) }
|
|
129
|
+
}
|
|
130
|
+
#[cfg(not(target_arch = "wasm32"))]
|
|
131
|
+
{
|
|
132
|
+
let _ = (offset_low, offset_high, max_bytes);
|
|
133
|
+
0
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
pub fn file_worker_write_chunk(ptr: usize, len: i32) {
|
|
138
|
+
#[cfg(target_arch = "wasm32")]
|
|
139
|
+
unsafe {
|
|
140
|
+
host_file_worker_write_chunk(ptr, len);
|
|
141
|
+
}
|
|
142
|
+
#[cfg(not(target_arch = "wasm32"))]
|
|
143
|
+
{
|
|
144
|
+
let _ = (ptr, len);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
pub fn worker_text_buffer_ptr() -> usize {
|
|
149
|
+
WORKER_CALLBACK_BUFFER.with(|buffer| buffer.borrow().as_ptr() as usize)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
pub fn worker_text_buffer_size() -> u32 {
|
|
153
|
+
WORKER_CALLBACK_BUFFER.with(|buffer| buffer.borrow().len() as u32)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
pub fn handle_fetch_complete(
|
|
157
|
+
request_id: u32,
|
|
158
|
+
ok: bool,
|
|
159
|
+
status: i32,
|
|
160
|
+
payload_ptr: *const u8,
|
|
161
|
+
payload_len: u32,
|
|
162
|
+
) {
|
|
163
|
+
crate::fetch::__fui_on_fetch_complete(request_id, ok, status, payload_ptr, payload_len);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
pub fn handle_fetch_error(request_id: u32, payload_ptr: *const u8, payload_len: u32) {
|
|
167
|
+
crate::fetch::__fui_on_fetch_error(request_id, payload_ptr, payload_len);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
pub fn reset_worker_runtime() {
|
|
171
|
+
WORKER_TERMINAL_SENT.with(|sent| sent.set(false));
|
|
172
|
+
}
|