initiative_core/world/
field.rs

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