1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use crate::{
DomNode, JsJson,
dev::LongPtr,
driver_module::{
api::{api_arguments, api_command_wasm, api_server_handler},
driver::get_driver,
get_driver_dom,
init_env::init_env,
},
};
/// Starting point of the app (used by [vertigo::main] macro, which is preferred)
pub fn start_app(init_app: fn() -> DomNode) {
mount(init_app)
}
/// What [`start_app`] does, minus the `fn` pointer - so a test can drive it with a closure
/// that captures.
pub(crate) fn mount(init_app: impl FnOnce() -> DomNode) {
init_env();
// Before the transaction, deliberately: `get_driver()` is what registers the flush hook,
// and the transaction below only suppresses mid-build flushes if it is the outermost one.
let driver = get_driver();
// The mount has to reach the browser as a single DOM batch. Hydration gets one shot, and
// it starts its walk from `<body>` - which is created late, after the whole `<head>`
// subtree and after anything the app built before reaching its top-level `dom!`.
// Without this transaction the first `Computed::subscribe` inside the tree closes an
// outermost transaction of its own, fires the flush hook, and ships a partial batch
// with no `<html>`/`<head>`/`<body>` in it.
driver.transaction(|_| {
let root_view = init_app();
driver.set_root(root_view);
});
// `flush_watch` - and so `when_connect` - runs *after* the hooks, so anything it queued is
// still sitting in the buffer. A no-op when the buffer is empty.
get_driver_dom().flush_dom_changes();
}
#[doc(hidden)]
#[unsafe(no_mangle)]
pub fn vertigo_export_handle_url(url_ptr: u64) -> u64 {
let url_ptr = LongPtr::from(url_ptr);
let url = api_arguments().get_by_long_ptr(url_ptr);
let JsJson::String(url) = url else {
panic!("string expected");
};
let response = api_server_handler().handler(&url);
response.to_ptr_long().get_long_ptr()
}
//------------------------------------------------------------------------------------------------------------------
// Internals below
//------------------------------------------------------------------------------------------------------------------
// Methods for memory allocation
#[doc(hidden)]
#[unsafe(no_mangle)]
pub fn vertigo_export_alloc_block(size: u32) -> u64 {
api_arguments().alloc(size).get_long_ptr()
}
#[doc(hidden)]
#[unsafe(no_mangle)]
pub fn vertigo_export_free_block(long_ptr: u64) {
let long_ptr = LongPtr::from(long_ptr);
api_arguments().free(long_ptr);
}
// Callbacks gateways
#[doc(hidden)]
#[unsafe(no_mangle)]
pub fn vertigo_export_wasm_command(value_long_ptr: u64) -> u64 {
let value_long_ptr = LongPtr::from(value_long_ptr);
let value = api_arguments().get_by_long_ptr(value_long_ptr);
let response = api_command_wasm().command_from_js(value);
response.to_ptr_long().get_long_ptr()
}