yew_state/
handler.rs

1//! State handlers determine how state should be created, modified, and shared.
2use 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
204/// Determines how state should be created, modified, and shared.
205pub trait StateHandler: Sized {
206    type Model: Clone;
207    type Message;
208    type Input;
209    type Output;
210
211    /// Create new state.
212    fn new(_link: HandlerLink<Self>) -> Self;
213
214    /// Return a reference to current state.
215    fn state(&mut self) -> &mut Rc<Self::Model>;
216
217    /// Called after state is changed.
218    fn changed(&mut self) {}
219
220    /// Receive messages from components.
221    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
231/// A direct bridge to given state handler. Unlike a [ServiceBridge](crate::service::ServiceBridge)
232/// bridge, it can only send and receive [StateHandler](StateHandler) messages.
233pub 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            // Service should only send messages to those who subscribe. We don't subscribe, so we
249            // shouldn't receive any messages here.
250            ServiceOutput::Service(_) => unreachable!(),
251        };
252
253        Self {
254            bridge: StateService::<_, SCOPE>::bridge(callback.into()),
255        }
256    }
257
258    /// Send a message to the state handler.
259    pub fn send(&mut self, msg: H::Input) {
260        self.bridge.send(ServiceInput::Handler(msg));
261    }
262}
263
264/// Handler for basic shared state.
265#[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
288/// Allows state to be stored persistently in local or session storage.
289pub trait Storable: Serialize + for<'a> Deserialize<'a> {
290    /// The key used to save and load state from storage.
291    fn key() -> &'static str {
292        type_name::<Self>()
293    }
294    /// The area to store state.
295    fn area() -> Area {
296        Area::Local
297    }
298}
299
300/// Handler for shared state with persistent storage.
301///
302/// If persistent storage is disabled it just behaves like a `SharedHandler`.
303#[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}