1use std::rc::Rc;
3
4use yew::{Callback, Properties};
5
6use crate::handler::{
7 HandlerLink, Reduction, ReductionOnce, SharedHandler, StateHandler, StorageHandler,
8};
9
10pub type SharedHandle<T> = StateHandle<SharedHandler<T>>;
12pub type StorageHandle<T> = StateHandle<StorageHandler<T>>;
15
16type Model<T> = <T as StateHandler>::Model;
17
18pub trait Handle {
19 type Handler: StateHandler;
20}
21
22impl<HANDLER> Handle for StateHandle<HANDLER>
23where
24 HANDLER: StateHandler,
25 <HANDLER as StateHandler>::Message: Clone,
26 <HANDLER as StateHandler>::Output: Clone,
27 <HANDLER as StateHandler>::Input: Clone,
28 Model<HANDLER>: Clone + 'static,
29{
30 type Handler = HANDLER;
31}
32
33pub trait SharedState {
34 type Handle: Handle;
35
36 fn handle(&mut self) -> &mut Self::Handle;
37}
38
39pub trait WrapperHandle: Handle {
41 fn set_state(&mut self, state: Rc<Model<Self::Handler>>);
42 fn set_callbacks(
43 &mut self,
44 callback: Callback<Reduction<Model<Self::Handler>>>,
45 callback_once: Callback<ReductionOnce<Model<Self::Handler>>>,
46 );
47 fn set_link(&mut self, _link: HandlerLink<Self::Handler>) {}
48}
49
50impl<HANDLER> WrapperHandle for StateHandle<HANDLER>
51where
52 HANDLER: StateHandler,
53 <HANDLER as StateHandler>::Message: Clone,
54 <HANDLER as StateHandler>::Output: Clone,
55 <HANDLER as StateHandler>::Input: Clone,
56 Model<HANDLER>: Clone + 'static,
57{
58 fn set_state(&mut self, state: Rc<Model<Self::Handler>>) {
59 self.state = Some(state);
60 }
61
62 fn set_link(&mut self, link: HandlerLink<Self::Handler>) {
63 self.link = Some(link);
64 }
65
66 fn set_callbacks(
67 &mut self,
68 callback: Callback<Reduction<Model<Self::Handler>>>,
69 callback_once: Callback<ReductionOnce<Model<Self::Handler>>>,
70 ) {
71 self.callback = callback;
72 self.callback_once = callback_once;
73 }
74}
75
76#[derive(Properties)]
78pub struct StateHandle<HANDLER>
79where
80 HANDLER: StateHandler,
81 <HANDLER as StateHandler>::Message: Clone,
82 <HANDLER as StateHandler>::Output: Clone,
83 <HANDLER as StateHandler>::Input: Clone,
84 Model<HANDLER>: Clone + 'static,
85{
86 #[prop_or_default]
87 state: Option<Rc<Model<HANDLER>>>,
88 #[prop_or_default]
89 callback: Callback<Reduction<Model<HANDLER>>>,
90 #[prop_or_default]
91 callback_once: Callback<ReductionOnce<Model<HANDLER>>>,
92 #[prop_or_default]
93 link: Option<HandlerLink<HANDLER>>,
94}
95
96impl<HANDLER> StateHandle<HANDLER>
97where
98 HANDLER: StateHandler,
99 <HANDLER as StateHandler>::Message: Clone,
100 <HANDLER as StateHandler>::Output: Clone,
101 <HANDLER as StateHandler>::Input: Clone,
102 Model<HANDLER>: Clone + 'static,
103{
104 pub fn link(&self) -> &HandlerLink<HANDLER> {
105 self.link.as_ref().expect(
106 "Link accessed prematurely. Is your component wrapped in a SharedStateComponent?",
107 )
108 }
109
110 pub fn state(&self) -> &Model<HANDLER> {
111 self.state.as_ref().expect(
112 "State accessed prematurely. Is your component wrapped in a SharedStateComponent?",
113 )
114 }
115
116 pub fn reduce(&self, f: impl FnOnce(&mut Model<HANDLER>) + 'static) {
119 self.callback_once.emit(Box::new(f))
120 }
121
122 pub fn reduce_callback<E: 'static>(
125 &self,
126 f: impl Fn(&mut Model<HANDLER>) + 'static,
127 ) -> Callback<E>
128 where
129 Model<HANDLER>: 'static,
130 {
131 let f = Rc::new(f);
132 self.callback.reform(move |_| f.clone())
133 }
134
135 pub fn reduce_callback_once<E: 'static>(
138 &self,
139 f: impl FnOnce(&mut Model<HANDLER>) + 'static,
140 ) -> Callback<E>
141 where
142 Model<HANDLER>: 'static,
143 {
144 let f = Box::new(f);
145 let cb = self.callback_once.clone();
146 Callback::once(move |_| cb.emit(f))
147 }
148
149 pub fn reduce_callback_with<E: 'static>(
152 &self,
153 f: impl Fn(&mut Model<HANDLER>, E) + 'static,
154 ) -> Callback<E>
155 where
156 Model<HANDLER>: 'static,
157 E: Clone,
158 {
159 let f = Rc::new(f);
160 self.callback.reform(move |e: E| {
161 let f = f.clone();
162 Rc::new(move |state| f.clone()(state, e.clone()))
163 })
164 }
165
166 pub fn reduce_callback_once_with<E: 'static>(
169 &self,
170 f: impl FnOnce(&mut Model<HANDLER>, E) + 'static,
171 ) -> Callback<E>
172 where
173 Model<HANDLER>: 'static,
174 {
175 let cb = self.callback_once.clone();
176 Callback::once(move |e| cb.emit(Box::new(move |state| f(state, e))))
177 }
178}
179
180impl<HANDLER> SharedState for StateHandle<HANDLER>
181where
182 HANDLER: StateHandler,
183 <HANDLER as StateHandler>::Message: Clone,
184 <HANDLER as StateHandler>::Output: Clone,
185 <HANDLER as StateHandler>::Input: Clone,
186 Model<HANDLER>: Clone,
187{
188 type Handle = Self;
189
190 fn handle(&mut self) -> &mut Self::Handle {
191 self
192 }
193}
194
195impl<HANDLER> Default for StateHandle<HANDLER>
196where
197 HANDLER: StateHandler,
198 <HANDLER as StateHandler>::Message: Clone,
199 <HANDLER as StateHandler>::Output: Clone,
200 <HANDLER as StateHandler>::Input: Clone,
201 Model<HANDLER>: Clone,
202{
203 fn default() -> Self {
204 Self {
205 state: Default::default(),
206 callback: Default::default(),
207 callback_once: Default::default(),
208 link: Default::default(),
209 }
210 }
211}
212
213impl<HANDLER> Clone for StateHandle<HANDLER>
214where
215 HANDLER: StateHandler,
216 HandlerLink<HANDLER>: Clone,
217 <HANDLER as StateHandler>::Message: Clone,
218 <HANDLER as StateHandler>::Output: Clone,
219 <HANDLER as StateHandler>::Input: Clone,
220 Model<HANDLER>: Clone,
221{
222 fn clone(&self) -> Self {
223 Self {
224 state: self.state.clone(),
225 callback: self.callback.clone(),
226 callback_once: self.callback_once.clone(),
227 link: self.link.clone(),
228 }
229 }
230}
231
232impl<HANDLER> PartialEq for StateHandle<HANDLER>
233where
234 HANDLER: StateHandler,
235 <HANDLER as StateHandler>::Message: Clone,
236 <HANDLER as StateHandler>::Output: Clone,
237 <HANDLER as StateHandler>::Input: Clone,
238 Model<HANDLER>: Clone,
239{
240 fn eq(&self, other: &Self) -> bool {
241 self.state
242 .as_ref()
243 .zip(other.state.as_ref())
244 .map(|(a, b)| Rc::ptr_eq(a, b))
245 .unwrap_or(false)
246 && self.callback == other.callback
247 && self.callback_once == other.callback_once
248 }
249}