Skip to main content

ratatui_kit/hooks/
use_state.rs

1// 响应式状态管理 Hook 实现。
2//
3// 本模块为 ratatui-kit 提供了类似 React useState 的响应式状态管理能力,适用于计数器、输入框等本地状态。
4
5use std::task::Poll;
6
7use generational_box::{Owner, SyncStorage};
8
9use super::{Hook, Hooks};
10use crate::{ReactiveHandle, ReactiveMutNoUpdate, ReactiveMutRef, ReactiveRef, SingleWaker};
11
12mod private {
13    pub trait Sealed {}
14    impl Sealed for crate::hooks::Hooks<'_, '_> {}
15}
16
17// 响应式状态持有者。
18pub type State<T> = ReactiveHandle<T, SingleWaker>;
19// 状态的只读引用。
20pub type StateRef<'a, T> = ReactiveRef<'a, T, SingleWaker>;
21// 状态的可变引用,支持变更通知。
22pub type StateMutRef<'a, T> = ReactiveMutRef<'a, T, SingleWaker>;
23// 状态的可变引用,不触发变更通知。
24pub type StateMutNoUpdate<'a, T> = ReactiveMutNoUpdate<'a, T, SingleWaker>;
25
26pub trait UseState: private::Sealed {
27    // 为 [`Hooks`] 提供 use_state 方法,创建响应式状态。
28    fn use_state<T, F>(&mut self, init: F) -> State<T>
29    where
30        F: FnOnce() -> T,
31        T: Unpin + Send + Sync + 'static;
32}
33
34struct UseStateImpl<T>
35where
36    T: Unpin + Send + Sync + 'static,
37{
38    state: State<T>,
39    _storage: Owner<SyncStorage>,
40}
41
42impl<T> UseStateImpl<T>
43where
44    T: Unpin + Send + Sync + 'static,
45{
46    // use_state 的内部实现,持有状态和存储。
47    pub fn new(initial_value: T) -> Self {
48        let storage = Owner::default();
49        UseStateImpl {
50            state: State::new_in(&storage, initial_value),
51            _storage: storage,
52        }
53    }
54}
55
56impl<T> Hook for UseStateImpl<T>
57where
58    T: Unpin + Send + Sync + 'static,
59{
60    fn poll_change(&mut self, cx: &mut std::task::Context) -> std::task::Poll<()> {
61        self.state.poll_change(None, cx)
62    }
63}
64
65impl UseState for Hooks<'_, '_> {
66    fn use_state<T, F>(&mut self, init: F) -> State<T>
67    where
68        F: FnOnce() -> T,
69        T: Unpin + Send + Sync + 'static,
70    {
71        self.use_hook(move || UseStateImpl::new(init())).state
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78
79    // 经 UseStateImpl 持有 Owner 保活,即可在单测里拿到一个可用的 State<T>。
80    // holder 在作用域内存活 → 底层 generational-box 有效。
81
82    #[test]
83    fn add_and_sub_assign_mutate_value() {
84        let holder = UseStateImpl::new(0i32);
85        let mut state = holder.state;
86        state += 5;
87        assert_eq!(state.get(), 5);
88        state -= 2;
89        assert_eq!(state.get(), 3);
90    }
91
92    #[test]
93    fn mul_assign_mutates_value() {
94        let holder = UseStateImpl::new(3i32);
95        let mut state = holder.state;
96        state *= 4;
97        assert_eq!(state.get(), 12);
98    }
99
100    #[test]
101    fn set_overwrites_and_get_reads() {
102        let holder = UseStateImpl::new(10i32);
103        let mut state = holder.state;
104        state.set(99);
105        assert_eq!(state.get(), 99);
106    }
107
108    #[test]
109    fn copy_handles_share_storage() {
110        let holder = UseStateImpl::new(1i32);
111        let mut state = holder.state;
112        let state2 = state;
113        state += 41;
114        assert_eq!(state.get(), 42);
115        assert_eq!(state2.get(), 42);
116    }
117}