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
25#[doc(hidden)]
26pub struct UseEffectImpl<D> {
27 deps: Option<D>,
28}
29
30impl<D> Default for UseEffectImpl<D> {
31 fn default() -> Self {
32 Self { deps: None }
33 }
34}
35
36#[doc(hidden)]
37pub struct UseAsyncEffectImpl<D> {
38 f: Option<LocalBoxFuture<'static, ()>>,
39 deps: Option<D>,
40}
41
42impl<D> Default for UseAsyncEffectImpl<D> {
43 fn default() -> Self {
44 Self {
45 f: None,
46 deps: None,
47 }
48 }
49}
50
51impl<D: Unpin> Hook for UseAsyncEffectImpl<D> {
52 fn poll_change(&mut self, cx: &mut std::task::Context) -> std::task::Poll<()> {
53 if let Some(future) = self.f.as_mut()
54 && future.as_mut().poll(cx).is_ready()
55 {
56 self.f = None;
57 return Poll::Ready(());
58 }
59 Poll::Pending
60 }
61}
62
63impl<D: Unpin> Hook for UseEffectImpl<D> {}
64
65impl UseEffect for Hooks<'_, '_> {
66 fn use_effect<F, D>(&mut self, f: F, deps: D)
67 where
68 F: FnOnce(),
69 D: PartialEq + Unpin + 'static,
70 {
71 let hook = self.use_hook(UseEffectImpl::<D>::default);
72 if hook.deps.as_ref() != Some(&deps) {
73 f();
74 hook.deps = Some(deps);
75 }
76 }
77
78 fn use_async_effect<F, D>(&mut self, f: F, deps: D)
79 where
80 F: Future<Output = ()> + 'static,
81 D: PartialEq + Unpin + 'static,
82 {
83 let hook = self.use_hook(UseAsyncEffectImpl::<D>::default);
84
85 if hook.deps.as_ref() != Some(&deps) {
86 hook.f = Some(f.boxed_local());
87 hook.deps = Some(deps);
88 }
89 }
90}