1use 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}