@@ -8,23 +8,101 @@ use std::rc::Weak;
8
8
use serde:: { Deserialize , Serialize } ;
9
9
10
10
use super :: handler_id:: HandlerId ;
11
+ use super :: messages:: FromWorker ;
11
12
use super :: messages:: ToWorker ;
13
+ use super :: native_worker:: DedicatedWorker ;
12
14
use super :: native_worker:: NativeWorkerExt ;
13
15
use super :: traits:: Worker ;
14
- use super :: { Callback , Shared } ;
16
+ use super :: Callback ;
15
17
use crate :: codec:: Codec ;
16
18
17
19
pub ( crate ) type ToWorkerQueue < W > = Vec < ToWorker < W > > ;
18
20
pub ( crate ) type CallbackMap < W > = HashMap < HandlerId , Weak < dyn Fn ( <W as Worker >:: Output ) > > ;
19
21
20
- struct WorkerBridgeInner < W >
22
+ pub ( crate ) struct WorkerBridgeInner < W >
21
23
where
22
24
W : Worker ,
23
25
{
24
26
// When worker is loaded, queue becomes None.
25
- pending_queue : Shared < Option < ToWorkerQueue < W > > > ,
26
- callbacks : Shared < CallbackMap < W > > ,
27
- post_msg : Rc < dyn Fn ( ToWorker < W > ) > ,
27
+ pending_queue : RefCell < Option < ToWorkerQueue < W > > > ,
28
+ callbacks : RefCell < CallbackMap < W > > ,
29
+ native_worker : RefCell < Option < DedicatedWorker > > ,
30
+ post_msg : Box < dyn Fn ( & DedicatedWorker , ToWorker < W > ) > ,
31
+ }
32
+
33
+ impl < W > WorkerBridgeInner < W >
34
+ where
35
+ W : Worker + ' static ,
36
+ {
37
+ pub ( crate ) fn new < CODEC > ( native_worker : DedicatedWorker , callbacks : CallbackMap < W > ) -> Rc < Self >
38
+ where
39
+ CODEC : Codec ,
40
+ W :: Input : Serialize + for < ' de > Deserialize < ' de > ,
41
+ W :: Output : Serialize + for < ' de > Deserialize < ' de > ,
42
+ {
43
+ let worker = native_worker. clone ( ) ;
44
+
45
+ let pending_queue = RefCell :: new ( Some ( Vec :: new ( ) ) ) ;
46
+ let callbacks = RefCell :: new ( callbacks) ;
47
+ let native_worker = RefCell :: new ( Some ( native_worker) ) ;
48
+ let post_msg = move |worker : & DedicatedWorker , msg : ToWorker < W > | {
49
+ worker. post_packed_message :: < _ , CODEC > ( msg)
50
+ } ;
51
+
52
+ let self_ = Self {
53
+ pending_queue,
54
+ callbacks,
55
+ native_worker,
56
+ post_msg : Box :: new ( post_msg) ,
57
+ } ;
58
+ let self_ = Rc :: new ( self_) ;
59
+
60
+ let handler = {
61
+ let bridge_inner = Rc :: downgrade ( & self_) ;
62
+ // If all bridges are dropped then `self_` is dropped and `upgrade` returns `None`.
63
+ move |msg : FromWorker < W > | {
64
+ if let Some ( bridge_inner) = Weak :: upgrade ( & bridge_inner) {
65
+ match msg {
66
+ FromWorker :: WorkerLoaded => {
67
+ // Set pending queue to `None`. Unless `WorkerLoaded` is
68
+ // sent twice, this will always be `Some`.
69
+ if let Some ( pending_queue) = bridge_inner. take_queue ( ) {
70
+ // Will be `None` if the worker has been terminated.
71
+ if let Some ( worker) =
72
+ bridge_inner. native_worker . borrow_mut ( ) . as_ref ( )
73
+ {
74
+ // Send all pending messages.
75
+ for to_worker in pending_queue. into_iter ( ) {
76
+ ( bridge_inner. post_msg ) ( worker, to_worker) ;
77
+ }
78
+ }
79
+ }
80
+ }
81
+ FromWorker :: ProcessOutput ( id, output) => {
82
+ let mut callbacks = bridge_inner. callbacks . borrow_mut ( ) ;
83
+
84
+ if let Some ( m) = callbacks. get ( & id) {
85
+ if let Some ( m) = Weak :: upgrade ( m) {
86
+ m ( output) ;
87
+ } else {
88
+ // The bridge has been dropped.
89
+ callbacks. remove ( & id) ;
90
+ }
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+ } ;
97
+
98
+ worker. set_on_packed_message :: < _ , CODEC , _ > ( handler) ;
99
+
100
+ self_
101
+ }
102
+
103
+ fn take_queue ( & self ) -> Option < ToWorkerQueue < W > > {
104
+ self . pending_queue . borrow_mut ( ) . take ( )
105
+ }
28
106
}
29
107
30
108
impl < W > fmt:: Debug for WorkerBridgeInner < W >
@@ -49,10 +127,24 @@ where
49
127
m. push ( msg) ;
50
128
}
51
129
None => {
52
- ( self . post_msg ) ( msg) ;
130
+ if let Some ( worker) = self . native_worker . borrow ( ) . as_ref ( ) {
131
+ ( self . post_msg ) ( worker, msg) ;
132
+ }
53
133
}
54
134
}
55
135
}
136
+
137
+ /// Terminate the worker, no more messages can be sent after this.
138
+ fn terminate ( & self ) {
139
+ if let Some ( worker) = self . native_worker . borrow_mut ( ) . take ( ) {
140
+ worker. terminate ( ) ;
141
+ }
142
+ }
143
+
144
+ /// Returns true if the worker is terminated.
145
+ fn is_terminated ( & self ) -> bool {
146
+ self . native_worker . borrow ( ) . is_none ( )
147
+ }
56
148
}
57
149
58
150
impl < W > Drop for WorkerBridgeInner < W >
@@ -66,6 +158,15 @@ where
66
158
}
67
159
68
160
/// A connection manager for components interaction with workers.
161
+ ///
162
+ /// Dropping this object will send a disconnect message to the worker and drop
163
+ /// the callback if set, but will have no effect on forked bridges. Note that
164
+ /// the worker will still receive and process any messages sent over the bridge
165
+ /// up to that point, but the reply will not trigger a callback. If all forked
166
+ /// bridges for a worker are dropped, the worker will be sent a destroy message.
167
+ ///
168
+ /// To terminate the worker and stop execution immediately, use
169
+ /// [`terminate`](#method.terminate).
69
170
pub struct WorkerBridge < W >
70
171
where
71
172
W : Worker ,
@@ -84,26 +185,16 @@ where
84
185
self . inner . send_message ( ToWorker :: Connected ( self . id ) ) ;
85
186
}
86
187
87
- pub ( crate ) fn new < CODEC > (
188
+ pub ( crate ) fn new (
88
189
id : HandlerId ,
89
- native_worker : web_sys:: Worker ,
90
- pending_queue : Rc < RefCell < Option < ToWorkerQueue < W > > > > ,
91
- callbacks : Rc < RefCell < CallbackMap < W > > > ,
190
+ inner : Rc < WorkerBridgeInner < W > > ,
92
191
callback : Option < Callback < W :: Output > > ,
93
192
) -> Self
94
193
where
95
- CODEC : Codec ,
96
194
W :: Input : Serialize + for < ' de > Deserialize < ' de > ,
97
195
{
98
- let post_msg = move |msg : ToWorker < W > | native_worker. post_packed_message :: < _ , CODEC > ( msg) ;
99
-
100
196
let self_ = Self {
101
- inner : WorkerBridgeInner {
102
- pending_queue,
103
- callbacks,
104
- post_msg : Rc :: new ( post_msg) ,
105
- }
106
- . into ( ) ,
197
+ inner,
107
198
id,
108
199
_worker : PhantomData ,
109
200
_cb : callback,
@@ -146,6 +237,23 @@ where
146
237
147
238
self_
148
239
}
240
+
241
+ /// Immediately terminates the worker and stops any execution in progress,
242
+ /// for this and all forked bridges. All messages will be dropped without
243
+ /// the worker receiving them. No disconnect or destroy message is sent. Any
244
+ /// messages sent after this point are dropped (from this bridge or any
245
+ /// forks).
246
+ ///
247
+ /// For more details see
248
+ /// [`web_sys::Worker::terminate`](https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Worker.html#method.terminate).
249
+ pub fn terminate ( & self ) {
250
+ self . inner . terminate ( )
251
+ }
252
+
253
+ /// Returns true if the worker is terminated.
254
+ pub fn is_terminated ( & self ) -> bool {
255
+ self . inner . is_terminated ( )
256
+ }
149
257
}
150
258
151
259
impl < W > Drop for WorkerBridge < W >
0 commit comments