ratatui_kit/hooks/
use_state.rs1use 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
17pub type State<T> = ReactiveHandle<T, SingleWaker>;
19pub type StateRef<'a, T> = ReactiveRef<'a, T, SingleWaker>;
21pub type StateMutRef<'a, T> = ReactiveMutRef<'a, T, SingleWaker>;
23pub type StateMutNoUpdate<'a, T> = ReactiveMutNoUpdate<'a, T, SingleWaker>;
25
26pub trait UseState: private::Sealed {
27 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 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 #[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}