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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use Any;
use Pin;
/// ThreadProc is the "main function" for the thread
///
/// Without the wrapper types and trait bounds, it is essentially a:
/// ```rust,ignore
/// impl FnOnce() -> Future<Output=T>
/// ```
///
/// .. which is a function executed on the worker thread that returns a value as a future.
///
/// ## Why does it return a future?
/// If the thread's "main function" is sync Rust, the JS Event Loop is blocked
/// for the duration the thread is running. This means the thread essentially cannot
/// do anything async in JS (for example using js_sys/web_sys).
/// While wrapping a Rust async runtime such as tokio will work to drive pure-Rust futures,
/// it will still not allow interop with the JS Event Loop.
///
/// See <https://github.com/Pistonite/wasm-bindgen-spawn/issues/7> for related discussion
///
/// The only solution is for the entire thread's main function to be compiled as a future
/// which can then be driven co-operatively by the JS Event Loop.
/// This will also work for sync main functions - they will just need to be wrapped
/// to return `future::ready`
///
/// ## Why does the future not need to be `Send`?
/// If we add the trait bounds, the signature becomes
/// ```rust,ignore
/// impl FnOnce() -> ( Future<Output=T> + 'static ) + 'static where T: Send + 'static
/// ```
/// Note that both the `FnOnce` and the return value `T` need to be `Send`, but not the future
/// itself.
///
/// This is because in `wasm_bindgen`, JS Values are references to objects on a "heap" managed
/// by `wasm_bindgen`. As they are JS objects that are only valid in the current JS context,
/// attempting to dereference them in another JS context will cause disaster.
///
/// If we require the future to be `Send`, the benefit is that async threads don't need the
/// `FnOnce` wrapper - they can just take in a future from the caller. However, for a future
/// to be `Send`, values that are not `Send` cannot be used across `await`s. This is because
/// a `Send` future means the future can be sent to execute on any thread at any time, not just
/// the beginning. This will cause major interoperability issues with JS.
///
/// However, once the future is spawned, the future is only ever executed on the JS context it
/// is spawned in - so it does not require `Send`. On the other hand, values captured by the
/// thread are actually "sent" to that thread, so the `FnOnce` requires `Send`. Essentially,
/// this guarantees:
///
/// - No `JsValue` (or anything that is not `Send`) is passed from one thread to another.
/// - Once the thread spawns, new `JsValue`s created on the current thread can be freely used
/// within the future.
///
/// ## Unwind safety
/// Now we can go a step further rewriting the type closer to its actual form
/// ```rust,ignore
/// type ThreadProc = AssertUnwindSafe<
/// Box<
/// dyn FnOnce -> Pin<Box<dyn Future<Output=T> + 'static>> + Send + 'static
/// >
/// >;
/// ```
/// The only differences are:
/// - Now instead of pseudo code for `FnOnce` and `Future`, we put in the real, boxed form
/// - The whole thing is wrapped in `AssertUnwindSafe`.
///
/// The `UnwindSafe` trait does not add additional guarantees; it is only a marker to indicate
/// that potentially-inconsistent state is not easily observed by the caller.
///
/// In the threading model, the `Send` trait requirement from spawn already ensures that any
/// owned value is moved to the thread and not observable by the spawner, and shared values
/// are guarded by types like `Mutex` that have other mechanisms (i.e. poisoning) to observe panics.
/// Therefore we have a similar case to `std::thread::spawn` which also does not require
/// `UnwindSafe`.
///
/// The `AssertUnwindSafe` wrapper exists in the type to work around `wasm_bindgen`'s limitation
/// that anything crossing the JS-Rust boundary needs to be `UnwindSafe` when `panic=unwind`.
pub type ThreadProc =
;
// ThreadProc itself should just be a fat pointer
assert_eq_size!;
// value channels are used to send thread return values.
// if one thread panics, the inconsistent state is already
// not easily observable by other threads (see _worker_main in binding.rs)
// so we can assert unwind safety here
pub type WorkerResult = ;
pub type ValueSender = Sender;
pub type ValueReceiver = Receiver;
pub type ValueReceiverAsync = AsyncReceiver;
// the thread dispatch payload is the main function and the channel to send
// the result back
pub type DispatchPayload = ;
pub type DispatchSender = UnboundedSender;
pub type DispatchReceiver = UnboundedReceiver;
pub type SignalSender = Sender;
pub type SignalReceiver = Receiver;
/// Wrapper for a heap allocated value
// Value is a temporary reference to the heap-allocated return value
// of a thread. Since we are not touching the underlying value in any way,
// the raw pointer is just a number that is Send + Sync
unsafe
unsafe
/// Helper to generate a binding
pub use js_arg_vec;
pub use js_type;
pub use raw_ptr_type;