raui_core/
state.rs

1//! Widget state types
2
3use crate::props::{Props, PropsData, PropsError};
4use intuicio_data::type_hash::TypeHash;
5use std::sync::mpsc::Sender;
6
7#[derive(Debug, Clone)]
8pub enum StateError {
9    Props(PropsError),
10    CouldNotWriteChange,
11}
12
13#[derive(Debug, Clone)]
14pub enum StateChange {
15    Set(Props),
16    Include(Props),
17    Exclude(TypeHash),
18}
19
20#[derive(Clone)]
21pub struct StateUpdate(Sender<StateChange>);
22
23impl StateUpdate {
24    pub fn new(sender: Sender<StateChange>) -> Self {
25        Self(sender)
26    }
27
28    pub fn set<T>(&self, data: T) -> Result<(), StateError>
29    where
30        T: Into<Props>,
31    {
32        if self.0.send(StateChange::Set(data.into())).is_err() {
33            Err(StateError::CouldNotWriteChange)
34        } else {
35            Ok(())
36        }
37    }
38
39    pub fn include<T>(&self, data: T) -> Result<(), StateError>
40    where
41        T: Into<Props>,
42    {
43        let data = data.into();
44        if self.0.send(StateChange::Include(data)).is_err() {
45            Err(StateError::CouldNotWriteChange)
46        } else {
47            Ok(())
48        }
49    }
50
51    pub fn exclude<T>(&self) -> Result<(), StateError>
52    where
53        T: 'static + PropsData,
54    {
55        if self
56            .0
57            .send(StateChange::Exclude(TypeHash::of::<T>()))
58            .is_err()
59        {
60            Err(StateError::CouldNotWriteChange)
61        } else {
62            Ok(())
63        }
64    }
65}
66
67pub struct State<'a> {
68    data: &'a Props,
69    update: StateUpdate,
70}
71
72impl<'a> State<'a> {
73    pub fn new(data: &'a Props, update: StateUpdate) -> Self {
74        Self { data, update }
75    }
76
77    #[inline]
78    pub fn data(&self) -> &Props {
79        self.data
80    }
81
82    pub fn has<T>(&self) -> bool
83    where
84        T: 'static + PropsData,
85    {
86        self.data.has::<T>()
87    }
88
89    pub fn read<T>(&self) -> Result<&'a T, StateError>
90    where
91        T: 'static + PropsData,
92    {
93        match self.data.read() {
94            Ok(v) => Ok(v),
95            Err(e) => Err(StateError::Props(e)),
96        }
97    }
98
99    pub fn map_or_default<T, R, F>(&self, f: F) -> R
100    where
101        T: 'static + PropsData,
102        R: Default,
103        F: FnMut(&T) -> R,
104    {
105        self.data.map_or_default(f)
106    }
107
108    pub fn map_or_else<T, R, F, E>(&self, f: F, e: E) -> R
109    where
110        T: 'static + PropsData,
111        F: FnMut(&T) -> R,
112        E: FnMut() -> R,
113    {
114        self.data.map_or_else(f, e)
115    }
116
117    pub fn read_cloned<T>(&self) -> Result<T, StateError>
118    where
119        T: 'static + PropsData + Clone,
120    {
121        match self.data.read_cloned() {
122            Ok(v) => Ok(v),
123            Err(e) => Err(StateError::Props(e)),
124        }
125    }
126
127    pub fn read_cloned_or_default<T>(&self) -> T
128    where
129        T: 'static + PropsData + Clone + Default,
130    {
131        self.data.read_cloned_or_default()
132    }
133
134    pub fn read_cloned_or_else<T, F>(&self, f: F) -> T
135    where
136        T: 'static + PropsData + Clone + Default,
137        F: FnMut() -> T,
138    {
139        self.data.read_cloned_or_else(f)
140    }
141
142    pub fn write<T>(&self, data: T) -> Result<(), StateError>
143    where
144        T: 'static + PropsData + Send + Sync,
145    {
146        self.update.set(data)
147    }
148
149    pub fn write_with<T>(&self, data: T) -> Result<(), StateError>
150    where
151        T: 'static + PropsData + Send + Sync,
152    {
153        self.update.include(data)
154    }
155
156    pub fn write_without<T>(&self) -> Result<(), StateError>
157    where
158        T: 'static + PropsData + Send + Sync,
159    {
160        self.update.exclude::<T>()
161    }
162
163    pub fn mutate<T, F>(&self, mut f: F) -> Result<(), StateError>
164    where
165        T: 'static + PropsData + Send + Sync,
166        F: FnMut(&T) -> T,
167    {
168        match self.read() {
169            Ok(data) => {
170                let data = f(data);
171                self.write(data)
172            }
173            Err(error) => Err(error),
174        }
175    }
176
177    pub fn mutate_cloned<T, F>(&self, mut f: F) -> Result<(), StateError>
178    where
179        T: 'static + PropsData + Send + Sync + Clone,
180        F: FnMut(&mut T),
181    {
182        match self.read::<T>() {
183            Ok(data) => {
184                let mut data = data.clone();
185                f(&mut data);
186                self.write(data)
187            }
188            Err(error) => Err(error),
189        }
190    }
191
192    pub fn update(&self) -> &StateUpdate {
193        &self.update
194    }
195}