@@ -8,23 +8,101 @@ use std::rc::Weak;
88use serde:: { Deserialize , Serialize } ;
99
1010use super :: handler_id:: HandlerId ;
11+ use super :: messages:: FromWorker ;
1112use super :: messages:: ToWorker ;
13+ use super :: native_worker:: DedicatedWorker ;
1214use super :: native_worker:: NativeWorkerExt ;
1315use super :: traits:: Worker ;
14- use super :: { Callback , Shared } ;
16+ use super :: Callback ;
1517use crate :: codec:: Codec ;
1618
1719pub ( crate ) type ToWorkerQueue < W > = Vec < ToWorker < W > > ;
1820pub ( crate ) type CallbackMap < W > = HashMap < HandlerId , Weak < dyn Fn ( <W as Worker >:: Output ) > > ;
1921
20- struct WorkerBridgeInner < W >
22+ pub ( crate ) struct WorkerBridgeInner < W >
2123where
2224 W : Worker ,
2325{
2426 // 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+ }
28106}
29107
30108impl < W > fmt:: Debug for WorkerBridgeInner < W >
@@ -49,10 +127,24 @@ where
49127 m. push ( msg) ;
50128 }
51129 None => {
52- ( self . post_msg ) ( msg) ;
130+ if let Some ( worker) = self . native_worker . borrow ( ) . as_ref ( ) {
131+ ( self . post_msg ) ( worker, msg) ;
132+ }
53133 }
54134 }
55135 }
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+ }
56148}
57149
58150impl < W > Drop for WorkerBridgeInner < W >
@@ -66,6 +158,15 @@ where
66158}
67159
68160/// 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).
69170pub struct WorkerBridge < W >
70171where
71172 W : Worker ,
@@ -84,26 +185,16 @@ where
84185 self . inner . send_message ( ToWorker :: Connected ( self . id ) ) ;
85186 }
86187
87- pub ( crate ) fn new < CODEC > (
188+ pub ( crate ) fn new (
88189 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 > > ,
92191 callback : Option < Callback < W :: Output > > ,
93192 ) -> Self
94193 where
95- CODEC : Codec ,
96194 W :: Input : Serialize + for < ' de > Deserialize < ' de > ,
97195 {
98- let post_msg = move |msg : ToWorker < W > | native_worker. post_packed_message :: < _ , CODEC > ( msg) ;
99-
100196 let self_ = Self {
101- inner : WorkerBridgeInner {
102- pending_queue,
103- callbacks,
104- post_msg : Rc :: new ( post_msg) ,
105- }
106- . into ( ) ,
197+ inner,
107198 id,
108199 _worker : PhantomData ,
109200 _cb : callback,
@@ -146,6 +237,23 @@ where
146237
147238 self_
148239 }
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+ }
149257}
150258
151259impl < W > Drop for WorkerBridge < W >
0 commit comments