yew_agent/worker/
scope.rs1use std::cell::RefCell;
2use std::fmt;
3use std::future::Future;
4use std::rc::Rc;
5
6use serde::de::Deserialize;
7use serde::ser::Serialize;
8use wasm_bindgen_futures::spawn_local;
9
10use super::handler_id::HandlerId;
11use super::lifecycle::{WorkerLifecycleEvent, WorkerRunnable, WorkerState};
12use super::messages::FromWorker;
13use super::native_worker::{DedicatedWorker, NativeWorkerExt, WorkerSelf};
14use super::traits::Worker;
15use super::Shared;
16use crate::codec::Codec;
17
18pub struct WorkerDestroyHandle<W>
20where
21 W: Worker + 'static,
22{
23 scope: WorkerScope<W>,
24}
25
26impl<W: Worker> fmt::Debug for WorkerDestroyHandle<W> {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 f.write_str("WorkerDestroyHandle<_>")
29 }
30}
31
32impl<W> WorkerDestroyHandle<W>
33where
34 W: Worker,
35{
36 pub(crate) fn new(scope: WorkerScope<W>) -> Self {
37 Self { scope }
38 }
39}
40
41impl<W> Drop for WorkerDestroyHandle<W>
42where
43 W: Worker,
44{
45 fn drop(&mut self) {
46 self.scope.send(WorkerLifecycleEvent::Destroy);
47 }
48}
49
50pub struct WorkerScope<W: Worker> {
52 state: Shared<WorkerState<W>>,
53 post_msg: Rc<dyn Fn(FromWorker<W>)>,
54}
55
56impl<W: Worker> fmt::Debug for WorkerScope<W> {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 f.write_str("WorkerScope<_>")
59 }
60}
61
62impl<W: Worker> Clone for WorkerScope<W> {
63 fn clone(&self) -> Self {
64 WorkerScope {
65 state: self.state.clone(),
66 post_msg: self.post_msg.clone(),
67 }
68 }
69}
70
71impl<W> WorkerScope<W>
72where
73 W: Worker + 'static,
74{
75 pub(crate) fn new<CODEC>() -> Self
77 where
78 CODEC: Codec,
79 W::Output: Serialize + for<'de> Deserialize<'de>,
80 {
81 let post_msg = move |msg: FromWorker<W>| {
82 DedicatedWorker::worker_self().post_packed_message::<_, CODEC>(msg)
83 };
84
85 let state = Rc::new(RefCell::new(WorkerState::new()));
86 WorkerScope {
87 post_msg: Rc::new(post_msg),
88 state,
89 }
90 }
91
92 pub(crate) fn send(&self, event: WorkerLifecycleEvent<W>) {
94 let state = self.state.clone();
95
96 spawn_local(async move {
99 WorkerRunnable { state, event }.run();
100 });
101 }
102
103 pub fn respond(&self, id: HandlerId, output: W::Output) {
105 let msg = FromWorker::<W>::ProcessOutput(id, output);
106 (self.post_msg)(msg);
107 }
108
109 pub fn send_message<T>(&self, msg: T)
111 where
112 T: Into<W::Message>,
113 {
114 self.send(WorkerLifecycleEvent::Message(msg.into()));
115 }
116
117 pub fn callback<F, IN, M>(&self, function: F) -> Rc<dyn Fn(IN)>
119 where
120 M: Into<W::Message>,
121 F: Fn(IN) -> M + 'static,
122 {
123 let scope = self.clone();
124 let closure = move |input| {
125 let output = function(input).into();
126 scope.send(WorkerLifecycleEvent::Message(output));
127 };
128 Rc::new(closure)
129 }
130
131 pub fn callback_future<FN, FU, IN, M>(&self, function: FN) -> Rc<dyn Fn(IN)>
138 where
139 M: Into<W::Message>,
140 FU: Future<Output = M> + 'static,
141 FN: Fn(IN) -> FU + 'static,
142 {
143 let scope = self.clone();
144
145 let closure = move |input: IN| {
146 let future: FU = function(input);
147 scope.send_future(future);
148 };
149
150 Rc::new(closure)
151 }
152
153 pub fn send_future<F, M>(&self, future: F)
158 where
159 M: Into<W::Message>,
160 F: Future<Output = M> + 'static,
161 {
162 let scope = self.clone();
163 let js_future = async move {
164 let message: W::Message = future.await.into();
165 let cb = scope.callback(|m: W::Message| m);
166 (*cb)(message);
167 };
168 wasm_bindgen_futures::spawn_local(js_future);
169 }
170}