Skip to main content

ratatui_kit/
reactive_handle.rs

1use std::{
2    cmp,
3    collections::HashMap,
4    fmt::{self, Debug, Display, Formatter},
5    hash::{Hash, Hasher},
6    ops::{Deref, DerefMut},
7    task::{Context, Poll, Waker},
8};
9
10use generational_box::{AnyStorage, GenerationalBox, Owner, SyncStorage};
11
12use crate::ElementKey;
13
14pub trait Notifier: Default + Send + Sync + 'static {
15    fn wake(&mut self);
16    fn register(&mut self, key: Option<&ElementKey>, waker: Waker);
17    fn clear(&mut self);
18    fn remove(&mut self, _key: &ElementKey) {}
19}
20
21#[derive(Default)]
22#[doc(hidden)]
23pub struct SingleWaker {
24    waker: Option<Waker>,
25}
26
27impl Notifier for SingleWaker {
28    fn wake(&mut self) {
29        if let Some(waker) = self.waker.take() {
30            waker.wake();
31        }
32    }
33
34    fn register(&mut self, _key: Option<&ElementKey>, waker: Waker) {
35        self.waker = Some(waker);
36    }
37
38    fn clear(&mut self) {
39        self.waker = None;
40    }
41}
42
43#[derive(Default)]
44#[doc(hidden)]
45pub struct WakerMap {
46    wakers: HashMap<ElementKey, Waker>,
47}
48
49impl Notifier for WakerMap {
50    fn wake(&mut self) {
51        for waker in self.wakers.values() {
52            waker.wake_by_ref();
53        }
54    }
55
56    fn register(&mut self, key: Option<&ElementKey>, waker: Waker) {
57        if let Some(key) = key {
58            self.wakers.insert(key.clone(), waker);
59        }
60    }
61
62    fn clear(&mut self) {
63        self.wakers.clear();
64    }
65
66    fn remove(&mut self, key: &ElementKey) {
67        self.wakers.remove(key);
68    }
69}
70
71pub struct ReactiveValue<T, N> {
72    value: T,
73    notifier: N,
74    is_changed: bool,
75}
76
77// 响应式状态核心句柄。
78pub struct ReactiveHandle<T, N>
79where
80    T: Send + Sync + 'static,
81    N: Notifier,
82{
83    pub(crate) inner: GenerationalBox<ReactiveValue<T, N>, SyncStorage>,
84}
85
86impl<T, N> Clone for ReactiveHandle<T, N>
87where
88    T: Send + Sync + 'static,
89    N: Notifier,
90{
91    fn clone(&self) -> Self {
92        *self
93    }
94}
95
96impl<T, N> Copy for ReactiveHandle<T, N>
97where
98    T: Send + Sync + 'static,
99    N: Notifier,
100{
101}
102
103impl<T, N> ReactiveHandle<T, N>
104where
105    T: Send + Sync + 'static,
106    N: Notifier,
107{
108    pub(crate) fn new_in(owner: &Owner<SyncStorage>, value: T) -> Self {
109        Self {
110            inner: owner.insert(ReactiveValue {
111                value,
112                notifier: N::default(),
113                is_changed: false,
114            }),
115        }
116    }
117
118    // 仅 `use_atom`(atom 特性)用于参数同步/退订,故随 atom 特性门控,避免无特性时的 dead_code 警告。
119    #[cfg(feature = "atom")]
120    pub(crate) fn same_storage(&self, other: &Self) -> bool {
121        self.inner.ptr_eq(&other.inner)
122    }
123
124    #[cfg(feature = "atom")]
125    pub(crate) fn remove_waker(&self, key: &ElementKey) {
126        if let Ok(mut value) = self.inner.try_write() {
127            value.notifier.remove(key);
128        }
129    }
130
131    #[cfg(test)]
132    pub(crate) fn has_waker(&self, key: &ElementKey) -> bool
133    where
134        N: WakerLookup,
135    {
136        self.inner
137            .try_read()
138            .map(|value| value.notifier.has_waker(key))
139            .unwrap_or(false)
140    }
141
142    pub(crate) fn poll_change(&self, key: Option<&ElementKey>, cx: &mut Context<'_>) -> Poll<()> {
143        if let Ok(mut value) = self.inner.try_write() {
144            if value.is_changed {
145                value.is_changed = false;
146                value.notifier.clear();
147                Poll::Ready(())
148            } else {
149                value.notifier.register(key, cx.waker().clone());
150                Poll::Pending
151            }
152        } else {
153            Poll::Pending
154        }
155    }
156
157    // 尝试获取只读引用,失败时返回 None。
158    pub fn try_read(&'_ self) -> Option<ReactiveRef<'_, T, N>> {
159        self.inner
160            .try_read()
161            .ok()
162            .map(|inner| ReactiveRef { inner })
163    }
164
165    // 获取只读引用,失败时 panic。
166    pub fn read(&'_ self) -> ReactiveRef<'_, T, N> {
167        self.try_read()
168            .expect("attempt to read state while unavailable or already mutably borrowed")
169    }
170
171    // 尝试获取可变引用,支持变更通知,失败时返回 None。
172    pub fn try_write(&'_ self) -> Option<ReactiveMutRef<'_, T, N>> {
173        self.inner
174            .try_write()
175            .map(|inner| ReactiveMutRef {
176                inner,
177                is_deref_mut: false,
178            })
179            .ok()
180    }
181
182    // 获取可变引用,支持变更通知,失败时 panic。
183    pub fn write(&'_ self) -> ReactiveMutRef<'_, T, N> {
184        self.try_write()
185            .expect("attempt to write state while unavailable or already borrowed")
186    }
187
188    // 尝试获取可变引用,不触发变更通知,失败时返回 None。
189    pub fn try_write_no_update(&'_ self) -> Option<ReactiveMutNoUpdate<'_, T, N>> {
190        self.inner
191            .try_write()
192            .map(|inner| ReactiveMutNoUpdate { inner })
193            .ok()
194    }
195
196    // 获取可变引用,不触发变更通知,失败时 panic。
197    pub fn write_no_update(&'_ self) -> ReactiveMutNoUpdate<'_, T, N> {
198        self.try_write_no_update()
199            .expect("attempt to write state while unavailable or already borrowed")
200    }
201
202    // 设置状态值,触发变更通知。
203    pub fn set(&mut self, value: T) {
204        if let Some(mut current) = self.try_write() {
205            *current = value;
206        }
207    }
208
209    // 设置状态值,不触发变更通知。
210    pub fn set_no_update(&mut self, value: T) {
211        if let Some(mut current) = self.try_write_no_update() {
212            *current = value;
213        }
214    }
215}
216
217#[cfg(test)]
218pub(crate) trait WakerLookup {
219    fn has_waker(&self, key: &ElementKey) -> bool;
220}
221
222#[cfg(test)]
223impl WakerLookup for WakerMap {
224    fn has_waker(&self, key: &ElementKey) -> bool {
225        self.wakers.contains_key(key)
226    }
227}
228
229impl<T, N> ReactiveHandle<T, N>
230where
231    T: Send + Sync + Copy + 'static,
232    N: Notifier,
233{
234    pub fn get(&self) -> T {
235        *self.read()
236    }
237}
238
239#[cfg(feature = "atom")]
240impl<T> ReactiveHandle<T, WakerMap>
241where
242    T: Send + Sync + 'static,
243{
244    pub fn new(value: T) -> Self {
245        Self::new_in(&crate::atom::OWNER, value)
246    }
247}
248
249// 状态的只读引用。
250pub struct ReactiveRef<'a, T, N>
251where
252    T: 'static,
253    N: Notifier,
254{
255    inner: <SyncStorage as AnyStorage>::Ref<'a, ReactiveValue<T, N>>,
256}
257
258impl<T, N> Deref for ReactiveRef<'_, T, N>
259where
260    T: 'static,
261    N: Notifier,
262{
263    type Target = T;
264
265    fn deref(&self) -> &Self::Target {
266        &self.inner.value
267    }
268}
269
270// 状态的可变引用,支持变更通知。
271pub struct ReactiveMutRef<'a, T, N>
272where
273    T: 'static,
274    N: Notifier,
275{
276    inner: <SyncStorage as AnyStorage>::Mut<'a, ReactiveValue<T, N>>,
277    is_deref_mut: bool,
278}
279
280impl<T, N> Deref for ReactiveMutRef<'_, T, N>
281where
282    T: 'static,
283    N: Notifier,
284{
285    type Target = T;
286
287    fn deref(&self) -> &Self::Target {
288        &self.inner.value
289    }
290}
291
292impl<T, N> DerefMut for ReactiveMutRef<'_, T, N>
293where
294    T: 'static,
295    N: Notifier,
296{
297    fn deref_mut(&mut self) -> &mut Self::Target {
298        self.is_deref_mut = true;
299        &mut self.inner.value
300    }
301}
302
303impl<T, N> Drop for ReactiveMutRef<'_, T, N>
304where
305    T: 'static,
306    N: Notifier,
307{
308    fn drop(&mut self) {
309        if self.is_deref_mut {
310            self.inner.is_changed = true;
311            self.inner.notifier.wake();
312        }
313    }
314}
315
316// 状态的可变引用,不触发变更通知。
317pub struct ReactiveMutNoUpdate<'a, T, N>
318where
319    T: 'static,
320    N: Notifier,
321{
322    inner: <SyncStorage as AnyStorage>::Mut<'a, ReactiveValue<T, N>>,
323}
324
325impl<T, N> Deref for ReactiveMutNoUpdate<'_, T, N>
326where
327    T: 'static,
328    N: Notifier,
329{
330    type Target = T;
331
332    fn deref(&self) -> &Self::Target {
333        &self.inner.value
334    }
335}
336
337impl<T, N> DerefMut for ReactiveMutNoUpdate<'_, T, N>
338where
339    T: 'static,
340    N: Notifier,
341{
342    fn deref_mut(&mut self) -> &mut Self::Target {
343        &mut self.inner.value
344    }
345}
346
347impl<T, N> Debug for ReactiveHandle<T, N>
348where
349    T: Debug + Send + Sync + 'static,
350    N: Notifier,
351{
352    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
353        self.read().fmt(f)
354    }
355}
356
357impl<T, N> Display for ReactiveHandle<T, N>
358where
359    T: Display + Send + Sync + 'static,
360    N: Notifier,
361{
362    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
363        self.read().fmt(f)
364    }
365}
366
367impl<T, N> Hash for ReactiveHandle<T, N>
368where
369    T: Hash + Send + Sync + 'static,
370    N: Notifier,
371{
372    fn hash<H: Hasher>(&self, state: &mut H) {
373        self.read().hash(state)
374    }
375}
376
377impl<T, N> cmp::PartialEq<T> for ReactiveHandle<T, N>
378where
379    T: cmp::PartialEq<T> + Send + Sync + 'static,
380    N: Notifier,
381{
382    fn eq(&self, other: &T) -> bool {
383        *self.read() == *other
384    }
385}
386
387impl<T, N> cmp::PartialOrd<T> for ReactiveHandle<T, N>
388where
389    T: cmp::PartialOrd<T> + Send + Sync + 'static,
390    N: Notifier,
391{
392    fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
393        self.read().partial_cmp(other)
394    }
395}
396
397impl<T, N> cmp::PartialEq<ReactiveHandle<T, N>> for ReactiveHandle<T, N>
398where
399    T: cmp::PartialEq<T> + Send + Sync + 'static,
400    N: Notifier,
401{
402    fn eq(&self, other: &ReactiveHandle<T, N>) -> bool {
403        *self.read() == *other.read()
404    }
405}
406
407impl<T, N> cmp::PartialOrd<ReactiveHandle<T, N>> for ReactiveHandle<T, N>
408where
409    T: cmp::PartialOrd<T> + Send + Sync + 'static,
410    N: Notifier,
411{
412    fn partial_cmp(&self, other: &ReactiveHandle<T, N>) -> Option<cmp::Ordering> {
413        self.read().partial_cmp(&other.read())
414    }
415}
416
417impl<T, N> cmp::Eq for ReactiveHandle<T, N>
418where
419    T: cmp::Eq + Send + Sync + 'static,
420    N: Notifier,
421{
422}
423
424impl<T, N> std::ops::Add<T> for ReactiveHandle<T, N>
425where
426    T: std::ops::Add<Output = T> + Copy + Send + Sync + 'static,
427    N: Notifier,
428{
429    type Output = T;
430
431    fn add(self, rhs: T) -> T {
432        self.get() + rhs
433    }
434}
435
436impl<T, N> std::ops::AddAssign<T> for ReactiveHandle<T, N>
437where
438    T: std::ops::AddAssign<T> + Copy + Send + Sync + 'static,
439    N: Notifier,
440{
441    fn add_assign(&mut self, rhs: T) {
442        if let Some(mut current) = self.try_write() {
443            *current += rhs;
444        }
445    }
446}
447
448impl<T, N> std::ops::Sub<T> for ReactiveHandle<T, N>
449where
450    T: std::ops::Sub<Output = T> + Copy + Send + Sync + 'static,
451    N: Notifier,
452{
453    type Output = T;
454
455    fn sub(self, rhs: T) -> T {
456        self.get() - rhs
457    }
458}
459
460impl<T, N> std::ops::SubAssign<T> for ReactiveHandle<T, N>
461where
462    T: std::ops::SubAssign<T> + Copy + Send + Sync + 'static,
463    N: Notifier,
464{
465    fn sub_assign(&mut self, rhs: T) {
466        if let Some(mut current) = self.try_write() {
467            *current -= rhs;
468        }
469    }
470}
471
472impl<T, N> std::ops::Mul<T> for ReactiveHandle<T, N>
473where
474    T: std::ops::Mul<Output = T> + Copy + Send + Sync + 'static,
475    N: Notifier,
476{
477    type Output = T;
478
479    fn mul(self, rhs: T) -> T {
480        self.get() * rhs
481    }
482}
483
484impl<T, N> std::ops::MulAssign<T> for ReactiveHandle<T, N>
485where
486    T: std::ops::MulAssign<T> + Copy + Send + Sync + 'static,
487    N: Notifier,
488{
489    fn mul_assign(&mut self, rhs: T) {
490        if let Some(mut current) = self.try_write() {
491            *current *= rhs;
492        }
493    }
494}
495
496impl<T, N> std::ops::Div<T> for ReactiveHandle<T, N>
497where
498    T: std::ops::Div<Output = T> + Copy + Send + Sync + 'static,
499    N: Notifier,
500{
501    type Output = T;
502
503    fn div(self, rhs: T) -> T {
504        self.get() / rhs
505    }
506}
507
508impl<T, N> std::ops::DivAssign<T> for ReactiveHandle<T, N>
509where
510    T: std::ops::DivAssign<T> + Copy + Send + Sync + 'static,
511    N: Notifier,
512{
513    fn div_assign(&mut self, rhs: T) {
514        if let Some(mut current) = self.try_write() {
515            *current /= rhs;
516        }
517    }
518}