raui_core/
state.rs

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