ratatui_kit/hooks/
mod.rs

1#![allow(unused)]
2use crate::{
3    context::ContextStack,
4    render::{ComponentDrawer, ComponentUpdater},
5};
6use std::{
7    any::Any,
8    pin::Pin,
9    task::{Context, Poll},
10};
11mod use_context;
12pub use use_context::*;
13mod use_events;
14pub use use_events::*;
15mod use_future;
16pub use use_future::*;
17mod use_state;
18pub use use_state::*;
19mod use_memo;
20pub use use_memo::*;
21mod use_effect;
22pub use use_effect::*;
23
24#[cfg(feature = "router")]
25mod use_router;
26#[cfg(feature = "router")]
27pub use use_router::*;
28
29pub trait Hook: Unpin + Send {
30    fn poll_change(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<()> {
31        Poll::Pending
32    }
33
34    fn pre_component_update(&mut self, _updater: &mut ComponentUpdater) {}
35    fn post_component_update(&mut self, _updater: &mut ComponentUpdater) {}
36
37    fn pre_component_draw(&mut self, _drawer: &mut ComponentDrawer) {}
38    fn post_component_draw(&mut self, _drawer: &mut ComponentDrawer) {}
39}
40
41pub(crate) trait AnyHook: Hook {
42    fn any_self_mut(&mut self) -> &mut dyn Any;
43}
44
45impl<T: Hook + 'static> AnyHook for T {
46    fn any_self_mut(&mut self) -> &mut dyn Any {
47        self
48    }
49}
50
51impl Hook for Vec<Box<dyn AnyHook>> {
52    fn poll_change(mut self: Pin<&mut Self>, _cx: &mut Context) -> Poll<()> {
53        let mut is_ready = false;
54        for hook in self.iter_mut() {
55            if Pin::new(&mut **hook).poll_change(_cx).is_ready() {
56                is_ready = true;
57            }
58        }
59
60        if is_ready {
61            Poll::Ready(())
62        } else {
63            Poll::Pending
64        }
65    }
66
67    fn pre_component_update(&mut self, _updater: &mut ComponentUpdater) {
68        for hook in self.iter_mut() {
69            hook.pre_component_update(_updater);
70        }
71    }
72
73    fn post_component_update(&mut self, _updater: &mut ComponentUpdater) {
74        for hook in self.iter_mut() {
75            hook.post_component_update(_updater);
76        }
77    }
78
79    fn pre_component_draw(&mut self, _updater: &mut ComponentDrawer) {
80        for hook in self.iter_mut() {
81            hook.pre_component_draw(_updater);
82        }
83    }
84
85    fn post_component_draw(&mut self, _updater: &mut ComponentDrawer) {
86        for hook in self.iter_mut() {
87            hook.post_component_draw(_updater);
88        }
89    }
90}
91
92pub struct Hooks<'a, 'b: 'a> {
93    hooks: &'a mut Vec<Box<dyn AnyHook>>,
94    first_update: bool,
95    hook_index: usize,
96    pub(crate) context: Option<&'a ContextStack<'b>>,
97}
98
99impl<'a> Hooks<'a, '_> {
100    pub(crate) fn new(hooks: &'a mut Vec<Box<dyn AnyHook>>, first_update: bool) -> Self {
101        Self {
102            hooks,
103            first_update,
104            hook_index: 0,
105            context: None,
106        }
107    }
108
109    pub fn with_context_stack<'c, 'd>(
110        &'c mut self,
111        context: &'c ContextStack<'d>,
112    ) -> Hooks<'c, 'd> {
113        Hooks {
114            hooks: self.hooks,
115            first_update: self.first_update,
116            hook_index: self.hook_index,
117            context: Some(context),
118        }
119    }
120
121    pub fn use_hook<F, H>(&mut self, f: F) -> &mut H
122    where
123        F: FnOnce() -> H,
124        H: Hook + Unpin + 'static,
125    {
126        if self.first_update {
127            self.hooks.push(Box::new(f()));
128        }
129        let idx = self.hook_index;
130        self.hook_index += 1;
131
132        self.hooks
133            .get_mut(idx)
134            .and_then(|hook| hook.any_self_mut().downcast_mut::<H>())
135            .expect("Hook type mismatch, ensure the hook is of the correct type")
136    }
137}