yew_agent/worker/
bridge.rs1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::fmt;
4use std::marker::PhantomData;
5use std::rc::{Rc, Weak};
6
7use serde::{Deserialize, Serialize};
8
9use super::handler_id::HandlerId;
10use super::messages::ToWorker;
11use super::native_worker::NativeWorkerExt;
12use super::traits::Worker;
13use super::{Callback, Shared};
14use crate::codec::Codec;
15
16pub(crate) type ToWorkerQueue<W> = Vec<ToWorker<W>>;
17pub(crate) type CallbackMap<W> = HashMap<HandlerId, Weak<dyn Fn(<W as Worker>::Output)>>;
18
19struct WorkerBridgeInner<W>
20where
21 W: Worker,
22{
23 pending_queue: Shared<Option<ToWorkerQueue<W>>>,
25 callbacks: Shared<CallbackMap<W>>,
26 post_msg: Rc<dyn Fn(ToWorker<W>)>,
27}
28
29impl<W> fmt::Debug for WorkerBridgeInner<W>
30where
31 W: Worker,
32{
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 f.write_str("WorkerBridgeInner<_>")
35 }
36}
37
38impl<W> WorkerBridgeInner<W>
39where
40 W: Worker,
41{
42 fn send_message(&self, msg: ToWorker<W>) {
44 let mut pending_queue = self.pending_queue.borrow_mut();
45
46 match pending_queue.as_mut() {
47 Some(m) => {
48 m.push(msg);
49 }
50 None => {
51 (self.post_msg)(msg);
52 }
53 }
54 }
55}
56
57impl<W> Drop for WorkerBridgeInner<W>
58where
59 W: Worker,
60{
61 fn drop(&mut self) {
62 let destroy = ToWorker::Destroy;
63 self.send_message(destroy);
64 }
65}
66
67pub struct WorkerBridge<W>
69where
70 W: Worker,
71{
72 inner: Rc<WorkerBridgeInner<W>>,
73 id: HandlerId,
74 _worker: PhantomData<W>,
75 _cb: Option<Rc<dyn Fn(W::Output)>>,
76}
77
78impl<W> WorkerBridge<W>
79where
80 W: Worker,
81{
82 fn init(&self) {
83 self.inner.send_message(ToWorker::Connected(self.id));
84 }
85
86 pub(crate) fn new<CODEC>(
87 id: HandlerId,
88 native_worker: web_sys::Worker,
89 pending_queue: Rc<RefCell<Option<ToWorkerQueue<W>>>>,
90 callbacks: Rc<RefCell<CallbackMap<W>>>,
91 callback: Option<Callback<W::Output>>,
92 ) -> Self
93 where
94 CODEC: Codec,
95 W::Input: Serialize + for<'de> Deserialize<'de>,
96 {
97 let post_msg = move |msg: ToWorker<W>| native_worker.post_packed_message::<_, CODEC>(msg);
98
99 let self_ = Self {
100 inner: WorkerBridgeInner {
101 pending_queue,
102 callbacks,
103 post_msg: Rc::new(post_msg),
104 }
105 .into(),
106 id,
107 _worker: PhantomData,
108 _cb: callback,
109 };
110 self_.init();
111
112 self_
113 }
114
115 pub fn send(&self, msg: W::Input) {
117 let msg = ToWorker::ProcessInput(self.id, msg);
118 self.inner.send_message(msg);
119 }
120
121 pub fn fork<F>(&self, cb: Option<F>) -> Self
125 where
126 F: 'static + Fn(W::Output),
127 {
128 let cb = cb.map(|m| Rc::new(m) as Rc<dyn Fn(W::Output)>);
129 let handler_id = HandlerId::new();
130
131 if let Some(cb_weak) = cb.as_ref().map(Rc::downgrade) {
132 self.inner
133 .callbacks
134 .borrow_mut()
135 .insert(handler_id, cb_weak);
136 }
137
138 let self_ = Self {
139 inner: self.inner.clone(),
140 id: handler_id,
141 _worker: PhantomData,
142 _cb: cb,
143 };
144 self_.init();
145
146 self_
147 }
148}
149
150impl<W> Drop for WorkerBridge<W>
151where
152 W: Worker,
153{
154 fn drop(&mut self) {
155 let disconnected = ToWorker::Disconnected(self.id);
156 self.inner.send_message(disconnected);
157 }
158}
159
160impl<W> fmt::Debug for WorkerBridge<W>
161where
162 W: Worker,
163{
164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165 f.write_str("WorkerBridge<_>")
166 }
167}
168
169impl<W> PartialEq for WorkerBridge<W>
170where
171 W: Worker,
172{
173 fn eq(&self, rhs: &Self) -> bool {
174 self.id == rhs.id
175 }
176}