Skip to main content

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}