initiative_core/world/
field.rs1use serde::{Deserialize, Serialize, Serializer};
2use std::fmt;
3use std::mem;
4
5#[derive(Clone, Debug, Deserialize)]
6#[serde(from = "Option<T>")]
7pub enum Field<T> {
8 Locked(Option<T>),
9 Unlocked(Option<T>),
10}
11
12impl<T> Field<T> {
13 pub fn new(value: T) -> Self {
14 Self::Locked(Some(value))
15 }
16
17 #[cfg(test)]
18 pub fn new_generated(value: T) -> Self {
19 Self::Unlocked(Some(value))
20 }
21
22 pub fn is_locked(&self) -> bool {
23 matches!(self, Self::Locked(_))
24 }
25
26 pub fn is_unlocked(&self) -> bool {
27 !self.is_locked()
28 }
29
30 pub fn lock(&mut self) {
31 *self = match mem::take(self) {
32 Self::Unlocked(value) => Self::Locked(value),
33 field => field,
34 }
35 }
36
37 #[cfg(test)]
38 pub fn locked(mut self) -> Self {
39 self.lock();
40 self
41 }
42
43 pub fn unlock(&mut self) {
44 *self = match mem::take(self) {
45 Self::Locked(value) => Self::Unlocked(value),
46 field => field,
47 }
48 }
49
50 pub fn set_locked(&mut self, locked: bool) {
51 if locked {
52 self.lock();
53 } else {
54 self.unlock();
55 }
56 }
57
58 #[cfg(test)]
59 pub fn unlocked(mut self) -> Self {
60 self.unlock();
61 self
62 }
63
64 pub fn replace(&mut self, value: T) {
65 self.replace_with(|_| value);
66 }
67
68 pub fn replace_with<F: FnOnce(Option<T>) -> T>(&mut self, f: F) {
69 *self = match mem::take(self) {
70 Self::Unlocked(value) => Self::Unlocked(Some(f(value))),
71 field => field,
72 }
73 }
74
75 pub fn clear(&mut self) {
76 if let Self::Unlocked(_) = self {
77 *self = Self::Unlocked(None)
78 }
79 }
80
81 pub fn value(&self) -> Option<&T> {
82 match self {
83 Self::Locked(value) => value,
84 Self::Unlocked(value) => value,
85 }
86 .as_ref()
87 }
88
89 pub fn value_mut(&mut self) -> Option<&mut T> {
90 match self {
91 Self::Locked(value) => value,
92 Self::Unlocked(value) => value,
93 }
94 .as_mut()
95 }
96
97 pub fn is_some(&self) -> bool {
98 !self.is_none()
99 }
100
101 pub fn is_none(&self) -> bool {
102 self.value().is_none()
103 }
104
105 pub fn apply_diff(&mut self, other: &mut Self) {
106 if other.is_locked() {
107 mem::swap(self, other);
108 other.lock();
109 }
110 }
111}
112
113impl<T: Eq> Eq for Field<T> {}
114
115impl<T: PartialEq> PartialEq for Field<T> {
116 fn eq(&self, other: &Self) -> bool {
117 self.value() == other.value()
118 }
119}
120
121impl<T: std::cmp::Ord> std::cmp::Ord for Field<T> {
122 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
123 self.value().cmp(&other.value())
124 }
125}
126
127impl<T: std::cmp::PartialOrd> std::cmp::PartialOrd for Field<T> {
128 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
129 self.value().partial_cmp(&other.value())
130 }
131}
132
133impl<T> Default for Field<T> {
134 fn default() -> Self {
135 Self::Unlocked(None)
136 }
137}
138
139impl<T> From<T> for Field<T> {
140 fn from(value: T) -> Field<T> {
141 Self::new(value)
142 }
143}
144
145impl<T> From<Option<T>> for Field<T> {
146 fn from(value: Option<T>) -> Field<T> {
147 Field::Locked(value)
148 }
149}
150
151impl<T> From<Field<T>> for Option<T> {
152 fn from(field: Field<T>) -> Option<T> {
153 match field {
154 Field::Locked(value) => value,
155 Field::Unlocked(value) => value,
156 }
157 }
158}
159
160impl From<&str> for Field<String> {
161 fn from(value: &str) -> Field<String> {
162 Self::new(value.to_string())
163 }
164}
165
166impl From<Option<&str>> for Field<String> {
167 fn from(value: Option<&str>) -> Field<String> {
168 value.map(|s| s.to_string()).into()
169 }
170}
171
172impl<T: fmt::Display> fmt::Display for Field<T> {
173 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174 if let Some(value) = &self.value() {
175 write!(f, "{}", value)?;
176 }
177 Ok(())
178 }
179}
180
181impl<T: Serialize> Serialize for Field<T> {
182 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
183 where
184 S: Serializer,
185 {
186 match self.value() {
187 Some(v) => serializer.serialize_some(v),
188 None => serializer.serialize_none(),
189 }
190 }
191}
192
193#[cfg(test)]
194mod test {
195 use super::Field;
196
197 #[test]
198 fn default_test() {
199 let field: Field<bool> = Field::default();
200 assert!(!field.is_locked());
201 assert!(field.is_none());
202 }
203
204 #[test]
205 fn new_test() {
206 {
207 let field: Field<_> = Field::new("hello");
208 assert!(field.is_locked());
209 assert!(field.is_some());
210 assert_eq!(Some(&"hello"), field.value());
211 }
212
213 {
214 let field: Field<_> = Field::new_generated("goodbye");
215 assert!(!field.is_locked());
216 assert!(field.is_some());
217 assert_eq!(Some(&"goodbye"), field.value());
218 }
219 }
220
221 #[test]
222 fn lock_unlock_test() {
223 let mut field = Field::Unlocked(Some(false));
224
225 assert!(field.is_unlocked());
226 assert!(!field.is_locked());
227
228 field.lock();
229
230 assert!(!field.is_unlocked());
231 assert!(field.is_locked());
232
233 field.unlock();
234 assert!(field.is_unlocked());
235
236 field = field.locked();
237 assert!(field.is_locked());
238
239 field = field.unlocked();
240 assert!(field.is_unlocked());
241 }
242
243 #[test]
244 fn replace_with_test() {
245 let mut field: Field<_> = Field::default();
246
247 field.replace(1);
248 assert_eq!(Field::new_generated(1), field);
249
250 field.replace_with(|i| i.unwrap() + 1);
251 assert_eq!(Field::new_generated(2), field);
252
253 field.lock();
254
255 field.replace_with(|_| 3);
256 assert_eq!(Field::new(2), field);
257 }
258
259 #[test]
260 fn clear_test() {
261 let mut field: Field<_> = Field::new_generated(123);
262 field.clear();
263 assert!(field.is_none());
264
265 let mut field: Field<_> = Field::new(123);
266 field.clear();
267 assert!(field.is_some());
268 }
269
270 #[test]
271 fn serialize_test() {
272 let field: Field<_> = Field::new(123);
273 assert_eq!("123", serde_json::to_string(&field).unwrap());
274
275 let field: Field<bool> = Field::default();
276 assert_eq!("null", serde_json::to_string(&field).unwrap());
277 }
278
279 #[test]
280 fn deserialize_test() {
281 let field: Field<u8> = serde_json::from_str("123").unwrap();
282 assert_eq!(Field::Locked(Some(123)), field);
283
284 let field: Field<u8> = serde_json::from_str("null").unwrap();
285 assert_eq!(Field::Locked(None), field);
286 }
287
288 #[test]
289 fn partial_eq_test() {
290 assert_eq!(Field::Locked(Some(true)), Field::Locked(Some(true)));
291 assert_eq!(Field::Unlocked(Some(true)), Field::Locked(Some(true)));
292 assert_eq!(Field::Locked(Some(true)), Field::Unlocked(Some(true)));
293 assert_eq!(Field::Unlocked(Some(true)), Field::Unlocked(Some(true)));
294
295 assert_ne!(Field::Locked(None), Field::Locked(Some(true)));
296 assert_ne!(Field::Locked(Some(false)), Field::Locked(Some(true)));
297 }
298
299 #[test]
300 fn apply_diff_test() {
301 {
302 let mut field = Field::Locked(Some(false));
303 let mut diff = Field::Unlocked(None);
304 field.apply_diff(&mut diff);
305 assert_eq!(Field::Locked(Some(false)), field);
306 assert_eq!(Field::Unlocked(None), diff);
307 }
308
309 {
310 let mut field = Field::Locked(Some(false));
311 let mut diff = Field::Locked(Some(true));
312 field.apply_diff(&mut diff);
313 assert_eq!(Field::Locked(Some(true)), field);
314 assert_eq!(Field::Locked(Some(false)), diff);
315 }
316
317 {
318 let mut field = Field::Locked(Some(false));
319 let mut diff = Field::Locked(None);
320 field.apply_diff(&mut diff);
321 assert_eq!(Field::Locked(None), field);
322 assert_eq!(Field::Locked(Some(false)), diff);
323 }
324
325 {
326 let mut field = Field::Unlocked(Some(false));
327 let mut diff = Field::Locked(Some(true));
328 field.apply_diff(&mut diff);
329 assert_eq!(Field::Locked(Some(true)), field);
330 assert_eq!(Field::Locked(Some(false)), diff);
331 }
332 }
333}