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