1use std::fmt;
2use std::sync::Arc;
3
4use crate::effect::EffectDependencies;
5use crate::hook_context::with_hook_context;
6
7pub struct Callback<IN, OUT = ()> {
13 callback: Arc<dyn Fn(IN) -> OUT + Send + Sync>,
14}
15
16impl<IN, OUT> Clone for Callback<IN, OUT> {
17 fn clone(&self) -> Self {
18 Self {
19 callback: self.callback.clone(),
20 }
21 }
22}
23
24impl<IN, OUT> Callback<IN, OUT> {
25 pub fn new<F>(func: F) -> Self
27 where
28 F: Fn(IN) -> OUT + Send + Sync + 'static,
29 {
30 Self {
31 callback: Arc::new(func),
32 }
33 }
34
35 pub fn emit(&self, input: IN) -> OUT {
37 (self.callback)(input)
38 }
39
40 pub fn reform<F, T>(&self, func: F) -> Callback<T, OUT>
42 where
43 F: Fn(T) -> IN + Send + Sync + 'static,
44 IN: 'static,
45 OUT: 'static,
46 {
47 let callback = self.callback.clone();
48 Callback::new(move |input: T| {
49 let transformed = func(input);
50 callback(transformed)
51 })
52 }
53
54 pub fn filter_reform<F, T>(&self, func: F) -> Callback<T, Option<OUT>>
56 where
57 F: Fn(T) -> Option<IN> + Send + Sync + 'static,
58 IN: 'static,
59 OUT: 'static,
60 {
61 let callback = self.callback.clone();
62 Callback::new(move |input: T| func(input).map(|v| callback(v)))
63 }
64}
65
66impl<IN> Callback<IN> {
67 pub fn noop() -> Self {
70 Self::new(|_| {})
71 }
72}
73
74impl<IN, OUT> Default for Callback<IN, OUT>
75where
76 OUT: Default,
77{
78 fn default() -> Self {
79 Self::new(|_| OUT::default())
80 }
81}
82
83impl<IN, OUT, F> From<F> for Callback<IN, OUT>
84where
85 F: Fn(IN) -> OUT + Send + Sync + 'static,
86{
87 fn from(func: F) -> Self {
88 Self::new(func)
89 }
90}
91
92impl<IN, OUT> From<Arc<dyn Fn(IN) -> OUT + Send + Sync>> for Callback<IN, OUT> {
96 fn from(func: Arc<dyn Fn(IN) -> OUT + Send + Sync>) -> Self {
97 Self { callback: func }
98 }
99}
100
101impl<IN> From<Option<Callback<IN>>> for Callback<IN> {
103 fn from(opt: Option<Callback<IN>>) -> Self {
104 opt.unwrap_or_else(Self::noop)
105 }
106}
107
108impl<IN, OUT> fmt::Debug for Callback<IN, OUT> {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 f.debug_struct("Callback")
111 .field("callback", &"<function>")
112 .finish()
113 }
114}
115
116impl<IN, OUT> PartialEq for Callback<IN, OUT> {
117 fn eq(&self, other: &Self) -> bool {
118 Arc::ptr_eq(&self.callback, &other.callback)
120 }
121}
122
123pub trait IntoCallback<IN, OUT = ()> {
126 fn into_callback(self) -> Callback<IN, OUT>;
127}
128
129impl<IN, OUT, F> IntoCallback<IN, OUT> for F
130where
131 F: Fn(IN) -> OUT + Send + Sync + 'static,
132{
133 fn into_callback(self) -> Callback<IN, OUT> {
134 Callback::from(self)
135 }
136}
137
138impl<IN, OUT> IntoCallback<IN, OUT> for Callback<IN, OUT> {
139 fn into_callback(self) -> Callback<IN, OUT> {
140 self
141 }
142}
143
144pub trait IntoCallbackProp<T> {
147 fn into_callback_prop(self) -> T;
148}
149
150impl<F, IN, OUT> IntoCallbackProp<Callback<IN, OUT>> for F
152where
153 F: IntoCallback<IN, OUT>,
154{
155 fn into_callback_prop(self) -> Callback<IN, OUT> {
156 self.into_callback()
157 }
158}
159
160impl<F, IN, OUT> IntoCallbackProp<Option<Callback<IN, OUT>>> for F
162where
163 F: IntoCallback<IN, OUT>,
164{
165 fn into_callback_prop(self) -> Option<Callback<IN, OUT>> {
166 Some(self.into_callback())
167 }
168}
169
170impl<IN, OUT> Callback<IN, OUT>
171where
172 IN: 'static,
173{
174 pub fn from_fn<F>(func: F) -> Self
177 where
178 F: Fn(IN) -> OUT + Send + Sync + 'static,
179 {
180 Self::from(func)
181 }
182
183 pub fn constant(value: OUT) -> Self
185 where
186 OUT: Clone + Send + Sync + 'static,
187 {
188 Self::from(move |_| value.clone())
189 }
190
191 pub fn debug() -> Self
193 where
194 IN: std::fmt::Debug,
195 OUT: Default,
196 {
197 Self::from(|input| {
198 println!("Callback called with: {:?}", input);
199 OUT::default()
200 })
201 }
202
203 pub fn then<F, NextOut>(self, next: F) -> Callback<IN, NextOut>
206 where
207 F: Fn(OUT) -> NextOut + Send + Sync + 'static,
208 OUT: 'static,
209 {
210 Callback::from(move |input| {
211 let intermediate = self.emit(input);
212 next(intermediate)
213 })
214 }
215
216 pub fn map<F, NewOut>(self, mapper: F) -> Callback<IN, NewOut>
218 where
219 F: Fn(OUT) -> NewOut + Send + Sync + 'static,
220 OUT: 'static,
221 {
222 self.then(mapper)
223 }
224
225 pub fn filter<F>(self, predicate: F) -> Callback<IN, Option<OUT>>
227 where
228 F: Fn(&IN) -> bool + Send + Sync + 'static,
229 IN: Clone + 'static,
230 OUT: 'static,
231 {
232 Callback::from(move |input| {
233 if predicate(&input) {
234 Some(self.emit(input))
235 } else {
236 None
237 }
238 })
239 }
240
241 pub fn catch_unwind(self) -> Callback<IN, Result<OUT, String>>
243 where
244 IN: 'static,
245 OUT: 'static,
246 {
247 use std::panic::{AssertUnwindSafe, catch_unwind};
248 Callback::from(move |input| {
249 catch_unwind(AssertUnwindSafe(|| self.emit(input)))
250 .map_err(|_| "Callback panicked".to_string())
251 })
252 }
253}
254
255impl<IN, OUT> Callback<IN, OUT>
257where
258 IN: 'static,
259{
260 pub fn always(value: OUT) -> Self
262 where
263 OUT: Clone + Send + Sync + 'static,
264 {
265 Self::constant(value)
266 }
267
268 pub fn from_mut<F>(func: F) -> Self
270 where
271 F: FnMut(IN) -> OUT + Send + Sync + 'static,
272 {
273 use std::sync::Mutex;
274 let func = Mutex::new(func);
275 Self::from(move |input| {
276 let mut guard = func.lock().unwrap();
277 guard(input)
278 })
279 }
280}
281
282struct CallbackState<IN, OUT> {
284 prev_deps: Option<Box<dyn EffectDependencies>>,
286 callback: Option<Callback<IN, OUT>>,
288}
289
290impl<IN, OUT> CallbackState<IN, OUT> {
291 fn new() -> Self {
292 Self {
293 prev_deps: None,
294 callback: None,
295 }
296 }
297}
298
299pub fn use_callback<IN, OUT, F, Deps>(func: F, deps: impl Into<Option<Deps>>) -> Callback<IN, OUT>
334where
335 F: Fn(IN) -> OUT + Send + Sync + Clone + 'static,
336 Deps: EffectDependencies + Clone + PartialEq + 'static,
337 IN: 'static,
338 OUT: 'static,
339{
340 let deps = deps.into();
341 with_hook_context(|ctx| {
342 let index = ctx.next_hook_index();
343 let state_ref = ctx.get_or_init_state(index, || CallbackState::<IN, OUT>::new());
344
345 let _should_recreate = {
346 let mut state = state_ref.borrow_mut();
347
348 let should_recreate = match &deps {
350 None => {
351 state.callback.is_none()
353 }
354 Some(current_deps) => {
355 match &state.prev_deps {
357 None => {
358 true
360 }
361 Some(prev_deps) => {
362 !current_deps.deps_eq(prev_deps.as_ref())
364 }
365 }
366 }
367 };
368
369 if should_recreate {
370 let new_callback = Callback::from(func.clone());
372 state.callback = Some(new_callback);
373
374 if let Some(current_deps) = &deps {
376 state.prev_deps = Some(current_deps.clone_deps());
377 } else {
378 state.prev_deps = None;
379 }
380 }
381
382 should_recreate
383 };
384
385 let state = state_ref.borrow();
387 (*state
388 .callback
389 .as_ref()
390 .expect("Callback should be initialized"))
391 .clone()
392 })
393}