ratatui_kit/hooks/
use_effect.rs1use futures::{FutureExt, future::LocalBoxFuture};
2use std::task::Poll;
3
4use crate::{Hook, Hooks};
5
6mod private {
7 pub trait Sealed {}
8 impl Sealed for crate::Hooks<'_, '_> {}
9}
10
11pub trait UseEffect: private::Sealed {
12 fn use_effect<F, D>(&mut self, f: F, deps: D)
14 where
15 F: FnOnce(),
16 D: PartialEq + Unpin + 'static;
17
18 fn use_async_effect<F, D>(&mut self, f: F, deps: D)
20 where
21 F: Future<Output = ()> + 'static,
22 D: PartialEq + Unpin + 'static;
23}
24
25pub struct UseEffectImpl<D> {
26 deps: Option<D>,
27}
28
29impl<D> Default for UseEffectImpl<D> {
30 fn default() -> Self {
31 Self { deps: None }
32 }
33}
34
35pub struct UseAsyncEffectImpl<D> {
36 f: Option<LocalBoxFuture<'static, ()>>,
37 deps: Option<D>,
38}
39
40impl<D> Default for UseAsyncEffectImpl<D> {
41 fn default() -> Self {
42 Self {
43 f: None,
44 deps: None,
45 }
46 }
47}
48
49impl<D: Unpin> Hook for UseAsyncEffectImpl<D> {
50 fn poll_change(&mut self, cx: &mut std::task::Context) -> std::task::Poll<()> {
51 if let Some(future) = self.f.as_mut()
52 && future.as_mut().poll(cx).is_ready()
53 {
54 self.f = None;
55 return Poll::Ready(());
56 }
57 Poll::Pending
58 }
59}
60
61impl<D: Unpin> Hook for UseEffectImpl<D> {}
62
63impl UseEffect for Hooks<'_, '_> {
64 fn use_effect<F, D>(&mut self, f: F, deps: D)
65 where
66 F: FnOnce(),
67 D: PartialEq + Unpin + 'static,
68 {
69 let hook = self.use_hook(UseEffectImpl::<D>::default);
70 if hook.deps.as_ref() != Some(&deps) {
71 f();
72 hook.deps = Some(deps);
73 }
74 }
75
76 fn use_async_effect<F, D>(&mut self, f: F, deps: D)
77 where
78 F: Future<Output = ()> + 'static,
79 D: PartialEq + Unpin + 'static,
80 {
81 let hook = self.use_hook(UseAsyncEffectImpl::<D>::default);
82
83 if hook.deps.as_ref() != Some(&deps) {
84 hook.f = Some(f.boxed_local());
85 hook.deps = Some(deps);
86 }
87 }
88}