1use std::any::type_name;
3#[cfg(feature = "future")]
4use std::pin::Pin;
5use std::rc::Rc;
6
7use serde::{Deserialize, Serialize};
8#[cfg(feature = "future")]
9use std::future::Future;
10use yew::{
11 agent::{AgentLink, Bridge, Bridged, HandlerId},
12 format::Json,
13 services::{storage::Area, StorageService},
14 Callback,
15};
16#[cfg(feature = "future")]
17use yewtil::future::LinkFuture;
18
19use crate::service::{ServiceInput, ServiceOutput, StateService};
20
21pub(crate) type Reduction<T> = Rc<dyn Fn(&mut T)>;
22pub(crate) type ReductionOnce<T> = Box<dyn FnOnce(&mut T)>;
23pub type Changed = bool;
24
25pub(crate) trait AgentLinkWrapper {
26 type Message;
27 type Input;
28 type Output;
29
30 fn send_message(&self, msg: Self::Message);
31 fn send_input(&self, input: Self::Input);
32 fn respond(&self, who: HandlerId, output: Self::Output);
33 #[cfg(feature = "future")]
34 fn send_future(&self, future: Pin<Box<dyn Future<Output = Self::Message>>>);
35}
36
37impl<H, SCOPE> AgentLinkWrapper for AgentLink<StateService<H, SCOPE>>
38where
39 H: StateHandler,
40{
41 type Message = H::Message;
42 type Input = H::Input;
43 type Output = H::Output;
44
45 fn send_message(&self, msg: Self::Message) {
46 AgentLink::<StateService<H, SCOPE>>::send_message(self, msg)
47 }
48
49 fn send_input(&self, input: Self::Input) {
50 AgentLink::<StateService<H, SCOPE>>::send_input(self, ServiceInput::Handler(input))
51 }
52
53 fn respond(&self, who: HandlerId, output: Self::Output) {
54 AgentLink::<StateService<H, SCOPE>>::respond(self, who, ServiceOutput::Handler(output))
55 }
56
57 #[cfg(feature = "future")]
58 fn send_future(&self, future: Pin<Box<dyn Future<Output = Self::Message>>>) {
59 LinkFuture::send_future(self, future)
60 }
61}
62
63pub struct HandlerLink<H>
64where
65 H: StateHandler,
66{
67 link: Rc<dyn AgentLinkWrapper<Message = H::Message, Input = H::Input, Output = H::Output>>,
68}
69
70impl<H> Clone for HandlerLink<H>
71where
72 H: StateHandler,
73{
74 fn clone(&self) -> Self {
75 Self {
76 link: self.link.clone(),
77 }
78 }
79}
80
81type HandlerMsg<H> = <H as StateHandler>::Message;
82type HandlerInput<H> = <H as StateHandler>::Input;
83type HandlerOutput<H> = <H as StateHandler>::Output;
84
85impl<H: StateHandler> HandlerLink<H> {
86 pub(crate) fn new(
87 link: impl AgentLinkWrapper<
88 Message = HandlerMsg<H>,
89 Input = HandlerInput<H>,
90 Output = HandlerOutput<H>,
91 > + 'static,
92 ) -> Self {
93 Self {
94 link: Rc::new(link),
95 }
96 }
97
98 pub fn send_message<T>(&self, msg: T)
99 where
100 T: Into<HandlerMsg<H>>,
101 {
102 self.link.send_message(msg.into())
103 }
104
105 pub fn send_input<T>(&self, msg: T)
106 where
107 T: Into<HandlerInput<H>>,
108 {
109 self.link.send_input(msg.into())
110 }
111
112 pub fn respond<T>(&self, who: HandlerId, output: T)
113 where
114 T: Into<HandlerOutput<H>>,
115 {
116 self.link.respond(who, output.into())
117 }
118
119 pub fn callback<F, IN, M>(&self, function: F) -> Callback<IN>
120 where
121 HandlerInput<H>: 'static,
122 HandlerOutput<H>: 'static,
123 HandlerMsg<H>: 'static,
124 M: Into<HandlerMsg<H>>,
125 F: Fn(IN) -> M + 'static,
126 {
127 let link = self.link.clone();
128 let cb = move |x| {
129 let result = function(x);
130 link.send_message(result.into());
131 };
132
133 cb.into()
134 }
135
136 pub fn callback_once<F, IN, M>(&self, function: F) -> Callback<IN>
137 where
138 HandlerInput<H>: 'static,
139 HandlerOutput<H>: 'static,
140 HandlerMsg<H>: 'static,
141 M: Into<HandlerMsg<H>>,
142 F: FnOnce(IN) -> M + 'static,
143 {
144 let link = self.link.clone();
145 let cb = move |x| {
146 let result = function(x);
147 link.send_message(result.into());
148 };
149
150 Callback::once(cb)
151 }
152
153 #[cfg(feature = "future")]
154 pub fn send_future<F, M>(&self, future: F)
155 where
156 M: Into<HandlerMsg<H>>,
157 F: Future<Output = M> + 'static,
158 {
159 let future = async { future.await.into() };
160 self.link.send_future(Box::pin(future))
161 }
162
163 #[cfg(feature = "future")]
164 pub fn callback_future<FN, FU, IN, M>(&self, function: FN) -> yew::Callback<IN>
165 where
166 HandlerInput<H>: 'static,
167 HandlerOutput<H>: 'static,
168 HandlerMsg<H>: 'static,
169 M: Into<HandlerMsg<H>>,
170 FU: Future<Output = M> + 'static,
171 FN: Fn(IN) -> FU + 'static,
172 {
173 let link = self.link.clone();
174 let cb = move |x| {
175 let future = function(x);
176 let future = async { future.await.into() };
177 link.send_future(Box::pin(future));
178 };
179
180 cb.into()
181 }
182
183 #[cfg(feature = "future")]
184 pub fn callback_once_future<FN, FU, IN, M>(&self, function: FN) -> yew::Callback<IN>
185 where
186 HandlerInput<H>: 'static,
187 HandlerOutput<H>: 'static,
188 HandlerMsg<H>: 'static,
189 M: Into<HandlerMsg<H>>,
190 FU: Future<Output = M> + 'static,
191 FN: FnOnce(IN) -> FU + 'static,
192 {
193 let link = self.link.clone();
194 let cb = move |x| {
195 let future = function(x);
196 let future = async { future.await.into() };
197 link.send_future(Box::pin(future));
198 };
199
200 Callback::once(cb)
201 }
202}
203
204pub trait StateHandler: Sized {
206 type Model: Clone;
207 type Message;
208 type Input;
209 type Output;
210
211 fn new(_link: HandlerLink<Self>) -> Self;
213
214 fn state(&mut self) -> &mut Rc<Self::Model>;
216
217 fn changed(&mut self) {}
219
220 fn update(&mut self, _msg: Self::Message) -> Changed {
222 false
223 }
224
225 #[allow(unused_variables)]
226 fn handle_input(&mut self, msg: Self::Input, _who: HandlerId) -> Changed {
227 false
228 }
229}
230
231pub struct HandlerBridge<H, SCOPE = H>
234where
235 H: StateHandler + 'static,
236 SCOPE: 'static,
237{
238 bridge: Box<dyn Bridge<StateService<H, SCOPE>>>,
239}
240
241impl<H, SCOPE> HandlerBridge<H, SCOPE>
242where
243 H: StateHandler + 'static,
244{
245 pub fn new(callback: Callback<H::Output>) -> Self {
246 let callback = move |msg: ServiceOutput<H>| match msg {
247 ServiceOutput::Handler(msg) => callback.emit(msg),
248 ServiceOutput::Service(_) => unreachable!(),
251 };
252
253 Self {
254 bridge: StateService::<_, SCOPE>::bridge(callback.into()),
255 }
256 }
257
258 pub fn send(&mut self, msg: H::Input) {
260 self.bridge.send(ServiceInput::Handler(msg));
261 }
262}
263
264#[derive(Default, Clone)]
266pub struct SharedHandler<T> {
267 state: Rc<T>,
268}
269
270impl<T> StateHandler for SharedHandler<T>
271where
272 T: Clone + Default,
273{
274 type Model = T;
275 type Message = ();
276 type Input = ();
277 type Output = ();
278
279 fn new(_link: HandlerLink<Self>) -> Self {
280 Default::default()
281 }
282
283 fn state(&mut self) -> &mut Rc<Self::Model> {
284 &mut self.state
285 }
286}
287
288pub trait Storable: Serialize + for<'a> Deserialize<'a> {
290 fn key() -> &'static str {
292 type_name::<Self>()
293 }
294 fn area() -> Area {
296 Area::Local
297 }
298}
299
300#[derive(Default)]
304pub struct StorageHandler<T> {
305 state: Rc<T>,
306 storage: Option<StorageService>,
307}
308
309impl<T> StorageHandler<T>
310where
311 T: Storable + Default,
312{
313 pub fn new() -> Self {
314 let mut this: Self = Default::default();
315 this.storage = StorageService::new(T::area()).ok();
316 this.load_state();
317 this
318 }
319
320 pub fn load_state(&mut self) {
321 let result = self.storage.as_mut().map(|s| s.restore(T::key()));
322 if let Some(Json(Ok(state))) = result {
323 self.state = state;
324 }
325 }
326
327 pub fn save_state(&mut self) {
328 if let Some(storage) = &mut self.storage {
329 storage.store(T::key(), Json(&self.state));
330 }
331 }
332}
333
334impl<T> StateHandler for StorageHandler<T>
335where
336 T: Default + Clone + Storable,
337{
338 type Model = T;
339 type Message = ();
340 type Input = ();
341 type Output = ();
342
343 fn new(_link: HandlerLink<Self>) -> Self {
344 Self::new()
345 }
346
347 fn state(&mut self) -> &mut Rc<Self::Model> {
348 &mut self.state
349 }
350
351 fn changed(&mut self) {
352 self.save_state();
353 }
354}
355
356impl<T> Clone for StorageHandler<T>
357where
358 T: Default + Clone + Storable,
359{
360 fn clone(&self) -> Self {
361 let mut new = Self::new();
362 new.state = self.state.clone();
363 new
364 }
365}
366
367impl<T: Storable> Storable for Option<T> {
368 fn key() -> &'static str {
369 T::key()
370 }
371
372 fn area() -> Area {
373 T::area()
374 }
375}
376
377impl<T: Storable> Storable for Rc<T> {
378 fn key() -> &'static str {
379 T::key()
380 }
381
382 fn area() -> Area {
383 T::area()
384 }
385}