freya_core/lifecycle/writable_utils.rs
1use crate::prelude::*;
2
3/// A shared interface for types that provide reactive write access to a value of type `T`.
4///
5/// Implementors must provide [`WritableUtils::write_state`] and [`WritableUtils::peek_state`].
6/// All convenience methods ([`WritableUtils::set`], [`WritableUtils::set_if_modified`], etc.) are provided as defaults.
7pub trait WritableUtils<T: 'static> {
8 /// Get a mutable reference to the value, notifying subscribers.
9 fn write_state(&mut self) -> WriteRef<'static, T>;
10
11 /// Read the current value without subscribing to changes.
12 fn peek_state(&self) -> ReadRef<'static, T>;
13
14 /// Replace the current value and notify subscribers.
15 ///
16 /// # Example
17 ///
18 /// ```rust,no_run
19 /// # use freya::prelude::*;
20 /// let mut status = use_state(|| "idle");
21 ///
22 /// status.set("loading");
23 /// status.set("complete");
24 /// ```
25 fn set(&mut self, value: T) {
26 *self.write_state() = value;
27 }
28
29 /// Replace the value only if it differs from the current one.
30 ///
31 /// This prevents unnecessary re-renders when setting the same value repeatedly.
32 ///
33 /// # Example
34 ///
35 /// ```rust,no_run
36 /// # use freya::prelude::*;
37 /// let mut count = use_state(|| 0);
38 ///
39 /// // This will update and notify subscribers
40 /// count.set_if_modified(5);
41 ///
42 /// // This will do nothing (value is already 5)
43 /// count.set_if_modified(5);
44 /// ```
45 fn set_if_modified(&mut self, value: T)
46 where
47 T: PartialEq,
48 {
49 if *self.peek_state() != value {
50 self.set(value);
51 }
52 }
53
54 /// Replace the value if modified, then run a callback.
55 ///
56 /// # Example
57 ///
58 /// ```rust,no_run
59 /// # use freya::prelude::*;
60 /// let mut score = use_state(|| 0);
61 ///
62 /// score.set_if_modified_and_then(100, || {
63 /// println!("High score achieved!");
64 /// });
65 /// ```
66 fn set_if_modified_and_then(&mut self, value: T, then: impl FnOnce())
67 where
68 T: PartialEq,
69 {
70 if *self.peek_state() != value {
71 self.set(value);
72 then();
73 }
74 }
75
76 /// Modify the value via a closure with a single notification.
77 ///
78 /// # Example
79 ///
80 /// ```rust,no_run
81 /// # use freya::prelude::*;
82 /// let mut counter = use_state(|| 0);
83 ///
84 /// counter.with_mut(|mut value| {
85 /// *value += 1;
86 /// *value *= 2;
87 /// });
88 /// ```
89 fn with_mut(&mut self, with: impl FnOnce(WriteRef<'static, T>)) {
90 with(self.write_state());
91 }
92}
93
94impl<T: 'static> WritableUtils<T> for State<T> {
95 fn write_state(&mut self) -> WriteRef<'static, T> {
96 self.write()
97 }
98
99 fn peek_state(&self) -> ReadRef<'static, T> {
100 self.peek()
101 }
102}
103
104impl<T: 'static> WritableUtils<T> for Writable<T> {
105 fn write_state(&mut self) -> WriteRef<'static, T> {
106 self.write()
107 }
108
109 fn peek_state(&self) -> ReadRef<'static, T> {
110 self.peek()
111 }
112}