comtrya_lib/values/
mod.rs

1use std::{
2    cmp::Ordering,
3    ffi::OsString,
4    fmt::{Debug, Display},
5    path::PathBuf,
6};
7
8use serde::{
9    de::{Error as SError, SeqAccess, Visitor},
10    Deserialize, Deserializer, Serialize,
11};
12
13#[derive(Clone, PartialEq, PartialOrd)]
14pub enum Value {
15    Null,
16    String(String),
17    Number(Number),
18    List(Vec<Value>),
19}
20
21#[derive(Clone, PartialEq, PartialOrd)]
22pub struct Number {
23    inner: NumberVariant,
24}
25
26#[derive(Clone, Copy)]
27enum NumberVariant {
28    Unsigned(u64),
29    Signed(i64),
30    Float(f64),
31}
32
33impl Serialize for Value {
34    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
35    where
36        S: serde::Serializer,
37    {
38        match self {
39            Value::Null => serializer.serialize_unit(),
40            Value::Number(n) => n.serialize(serializer),
41            Value::String(s) => serializer.serialize_str(s),
42            Value::List(seq) => seq.serialize(serializer),
43        }
44    }
45}
46
47impl Serialize for Number {
48    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
49    where
50        S: serde::Serializer,
51    {
52        {
53            match self.inner {
54                NumberVariant::Unsigned(u) => serializer.serialize_u64(u),
55                NumberVariant::Signed(s) => serializer.serialize_i64(s),
56                NumberVariant::Float(f) => serializer.serialize_f64(f),
57            }
58        }
59    }
60}
61
62impl<'de> Deserialize<'de> for Value {
63    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
64    where
65        D: serde::Deserializer<'de>,
66    {
67        struct ValueVisitor;
68
69        impl<'de> Visitor<'de> for ValueVisitor {
70            type Value = Value;
71
72            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
73                formatter.write_str("any comtrya context value")
74            }
75
76            fn visit_i64<E>(self, i: i64) -> Result<Value, E>
77            where
78                E: SError,
79            {
80                Ok(Value::Number(Number {
81                    inner: NumberVariant::Signed(i),
82                }))
83            }
84
85            fn visit_u64<E>(self, u: u64) -> Result<Value, E>
86            where
87                E: SError,
88            {
89                Ok(Value::Number(Number {
90                    inner: NumberVariant::Unsigned(u),
91                }))
92            }
93
94            fn visit_f64<E>(self, f: f64) -> Result<Value, E>
95            where
96                E: SError,
97            {
98                Ok(Value::Number(Number {
99                    inner: NumberVariant::Float(f),
100                }))
101            }
102
103            fn visit_str<E>(self, s: &str) -> Result<Value, E>
104            where
105                E: SError,
106            {
107                Ok(Value::String(s.to_owned()))
108            }
109
110            fn visit_string<E>(self, s: String) -> Result<Value, E>
111            where
112                E: SError,
113            {
114                Ok(Value::String(s))
115            }
116
117            fn visit_unit<E>(self) -> Result<Value, E>
118            where
119                E: SError,
120            {
121                Ok(Value::Null)
122            }
123
124            fn visit_none<E>(self) -> Result<Value, E>
125            where
126                E: SError,
127            {
128                Ok(Value::Null)
129            }
130
131            fn visit_some<D>(self, deserializer: D) -> Result<Value, D::Error>
132            where
133                D: Deserializer<'de>,
134            {
135                Deserialize::deserialize(deserializer)
136            }
137
138            fn visit_seq<V>(self, mut visitor: V) -> Result<Value, V::Error>
139            where
140                V: SeqAccess<'de>,
141            {
142                let mut vec = Vec::new();
143
144                while let Some(element) = visitor.next_element()? {
145                    vec.push(element);
146                }
147
148                Ok(Value::List(vec))
149            }
150        }
151
152        deserializer.deserialize_any(ValueVisitor)
153    }
154}
155
156impl Debug for Value {
157    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158        match self {
159            Value::Null => formatter.write_str("Null"),
160            Value::String(string) => write!(formatter, "String({:?})", string),
161            Value::Number(number) => write!(formatter, "Number({})", number),
162            Value::List(list) => {
163                formatter.write_str("List ")?;
164                formatter.debug_list().entries(list).finish()
165            }
166        }
167    }
168}
169
170impl Debug for Number {
171    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172        write!(formatter, "Number({})", self)
173    }
174}
175
176impl Display for Number {
177    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178        match self.inner {
179            NumberVariant::Unsigned(number) => Display::fmt(&number, formatter),
180            NumberVariant::Signed(number) => Display::fmt(&number, formatter),
181            NumberVariant::Float(number) => Display::fmt(&number, formatter),
182        }
183    }
184}
185
186impl NumberVariant {
187    fn total_cmp(&self, other: &Self) -> Ordering {
188        match (*self, *other) {
189            (NumberVariant::Unsigned(a), NumberVariant::Unsigned(b)) => a.cmp(&b),
190            (NumberVariant::Signed(a), NumberVariant::Signed(b)) => a.cmp(&b),
191            (NumberVariant::Unsigned(a), NumberVariant::Signed(b)) => (a as i64).cmp(&b),
192            (NumberVariant::Signed(a), NumberVariant::Unsigned(b)) => a.cmp(&(b as i64)),
193            (NumberVariant::Float(a), NumberVariant::Float(b)) => {
194                // FIXME: change to total_cmp for Rust >= 1.62.0
195                a.partial_cmp(&b).unwrap_or_else(|| {
196                    // arbitrarily sort the NaN last
197                    if !a.is_nan() {
198                        Ordering::Less
199                    } else if !b.is_nan() {
200                        Ordering::Greater
201                    } else {
202                        Ordering::Equal
203                    }
204                })
205            }
206            (NumberVariant::Signed(a), NumberVariant::Float(b)) => {
207                // FIXME: change to total_cmp for Rust >= 1.62.0
208                (a as f64).partial_cmp(&b).unwrap_or_else(|| {
209                    // arbitrarily sort the NaN last
210                    if !(a as f64).is_nan() {
211                        Ordering::Less
212                    } else if !b.is_nan() {
213                        Ordering::Greater
214                    } else {
215                        Ordering::Equal
216                    }
217                })
218            }
219            (NumberVariant::Unsigned(a), NumberVariant::Float(b)) => {
220                // FIXME: change to total_cmp for Rust >= 1.62.0
221                (a as f64).partial_cmp(&b).unwrap_or_else(|| {
222                    // arbitrarily sort the NaN last
223                    if !(a as f64).is_nan() {
224                        Ordering::Less
225                    } else if !b.is_nan() {
226                        Ordering::Greater
227                    } else {
228                        Ordering::Equal
229                    }
230                })
231            }
232            (NumberVariant::Float(a), NumberVariant::Signed(b)) => {
233                // FIXME: change to total_cmp for Rust >= 1.62.0
234                a.partial_cmp(&(b as f64)).unwrap_or_else(|| {
235                    // arbitrarily sort the NaN last
236                    if !a.is_nan() {
237                        Ordering::Less
238                    } else if !(b as f64).is_nan() {
239                        Ordering::Greater
240                    } else {
241                        Ordering::Equal
242                    }
243                })
244            }
245            (NumberVariant::Float(a), NumberVariant::Unsigned(b)) => {
246                // FIXME: change to total_cmp for Rust >= 1.62.0
247                a.partial_cmp(&(b as f64)).unwrap_or_else(|| {
248                    // arbitrarily sort the NaN last
249                    if !a.is_nan() {
250                        Ordering::Less
251                    } else if !(b as f64).is_nan() {
252                        Ordering::Greater
253                    } else {
254                        Ordering::Equal
255                    }
256                })
257            }
258        }
259    }
260}
261
262impl PartialEq for NumberVariant {
263    fn eq(&self, other: &Self) -> bool {
264        match (*self, *other) {
265            (NumberVariant::Unsigned(a), NumberVariant::Unsigned(b)) => a == b,
266            (NumberVariant::Signed(a), NumberVariant::Signed(b)) => a == b,
267            (NumberVariant::Float(a), NumberVariant::Float(b)) => a == b,
268            (NumberVariant::Unsigned(a), NumberVariant::Signed(b)) => (a as i64) == b,
269            (NumberVariant::Signed(a), NumberVariant::Unsigned(b)) => a == (b as i64),
270            (NumberVariant::Unsigned(a), NumberVariant::Float(b)) => (a as f64) == b,
271            (NumberVariant::Signed(a), NumberVariant::Float(b)) => (a as f64) == b,
272            (NumberVariant::Float(a), NumberVariant::Unsigned(b)) => a == (b as f64),
273            (NumberVariant::Float(a), NumberVariant::Signed(b)) => a == (b as f64),
274        }
275    }
276}
277
278impl PartialOrd for NumberVariant {
279    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
280        Some(self.total_cmp(other))
281    }
282}
283
284impl From<String> for Value {
285    fn from(from: String) -> Self {
286        Value::String(from)
287    }
288}
289
290impl<'a> From<&'a str> for Value {
291    fn from(from: &'a str) -> Self {
292        Value::String(from.to_string())
293    }
294}
295
296impl<'a> From<std::borrow::Cow<'a, str>> for Value {
297    fn from(from: std::borrow::Cow<'a, str>) -> Self {
298        Value::String(from.to_string())
299    }
300}
301
302impl From<OsString> for Value {
303    fn from(from: OsString) -> Self {
304        Value::String(from.to_str().unwrap_or("unknown").to_string())
305    }
306}
307
308impl From<PathBuf> for Value {
309    fn from(from: PathBuf) -> Self {
310        Value::String(from.display().to_string())
311    }
312}
313
314impl<T: Into<Value>> From<Vec<T>> for Value {
315    fn from(from: Vec<T>) -> Self {
316        Value::List(from.into_iter().map(Into::into).collect())
317    }
318}
319
320impl ToString for Value {
321    fn to_string(&self) -> String {
322        match self {
323            Value::Null => "null".to_string(),
324            Value::String(string) => string.to_owned(),
325            Value::Number(number) => number.to_string(),
326            Value::List(list) => list
327                .iter()
328                .map(|value| value.to_string())
329                .collect::<Vec<String>>()
330                .join(","),
331        }
332    }
333}
334
335#[cfg(test)]
336mod test {
337    use std::{borrow::Cow, ffi::OsString, path::PathBuf};
338
339    use crate::values::{Number, NumberVariant, Value};
340    use anyhow::Ok;
341    use pretty_assertions::assert_eq;
342
343    #[test]
344    fn from_string_tests() -> anyhow::Result<()> {
345        assert_eq!(
346            Value::from("John Sheppard"),
347            Value::String("John Sheppard".to_string())
348        );
349
350        assert_eq!(
351            Value::from("Elizabeth Weir".to_string()),
352            Value::String("Elizabeth Weir".to_string())
353        );
354
355        assert_eq!(Value::from(PathBuf::new()), Value::String("".to_string()));
356
357        assert_eq!(
358            Value::from(Cow::from("Samantha Carter")),
359            Value::String("Samantha Carter".to_string())
360        );
361
362        assert_eq!(
363            Value::from(OsString::from("Jennifer Keller")),
364            Value::String("Jennifer Keller".to_string())
365        );
366
367        Ok(())
368    }
369
370    #[test]
371    fn from_vec_test() -> anyhow::Result<()> {
372        assert_eq!(
373            Value::from(vec!["Aiden Ford", "Rodney McKay", "Ronon Dex"]),
374            Value::List(vec![
375                Value::String("Aiden Ford".to_string()),
376                Value::String("Rodney McKay".to_string()),
377                Value::String("Ronon Dex".to_string())
378            ])
379        );
380
381        Ok(())
382    }
383
384    #[test]
385    fn number_compare_test() -> anyhow::Result<()> {
386        // unsigned
387        assert_eq!(
388            true,
389            Value::Number(Number {
390                inner: NumberVariant::Unsigned(2)
391            }) == Value::Number(Number {
392                inner: NumberVariant::Unsigned(2)
393            })
394        );
395
396        assert_eq!(
397            true,
398            Value::Number(Number {
399                inner: NumberVariant::Unsigned(3)
400            }) > Value::Number(Number {
401                inner: NumberVariant::Unsigned(2)
402            })
403        );
404
405        assert_eq!(
406            true,
407            Value::Number(Number {
408                inner: NumberVariant::Unsigned(2)
409            }) < Value::Number(Number {
410                inner: NumberVariant::Unsigned(3)
411            })
412        );
413
414        // signed
415        assert_eq!(
416            true,
417            Value::Number(Number {
418                inner: NumberVariant::Signed(2)
419            }) == Value::Number(Number {
420                inner: NumberVariant::Signed(2)
421            })
422        );
423
424        assert_eq!(
425            true,
426            Value::Number(Number {
427                inner: NumberVariant::Signed(3)
428            }) > Value::Number(Number {
429                inner: NumberVariant::Signed(2)
430            })
431        );
432
433        assert_eq!(
434            true,
435            Value::Number(Number {
436                inner: NumberVariant::Signed(2)
437            }) < Value::Number(Number {
438                inner: NumberVariant::Signed(3)
439            })
440        );
441
442        // float
443        assert_eq!(
444            true,
445            Value::Number(Number {
446                inner: NumberVariant::Float(2.0)
447            }) == Value::Number(Number {
448                inner: NumberVariant::Float(2.0)
449            })
450        );
451
452        assert_eq!(
453            true,
454            Value::Number(Number {
455                inner: NumberVariant::Float(3.0)
456            }) > Value::Number(Number {
457                inner: NumberVariant::Float(2.0)
458            })
459        );
460
461        assert_eq!(
462            true,
463            Value::Number(Number {
464                inner: NumberVariant::Float(2.0)
465            }) < Value::Number(Number {
466                inner: NumberVariant::Float(3.0)
467            })
468        );
469
470        // unsigned with signed
471        assert_eq!(
472            true,
473            Value::Number(Number {
474                inner: NumberVariant::Unsigned(2)
475            }) == Value::Number(Number {
476                inner: NumberVariant::Signed(2)
477            })
478        );
479
480        assert_eq!(
481            true,
482            Value::Number(Number {
483                inner: NumberVariant::Unsigned(3)
484            }) > Value::Number(Number {
485                inner: NumberVariant::Signed(2)
486            })
487        );
488
489        assert_eq!(
490            true,
491            Value::Number(Number {
492                inner: NumberVariant::Unsigned(2)
493            }) < Value::Number(Number {
494                inner: NumberVariant::Signed(3)
495            })
496        );
497
498        // signed with unsigned
499        assert_eq!(
500            true,
501            Value::Number(Number {
502                inner: NumberVariant::Signed(2)
503            }) == Value::Number(Number {
504                inner: NumberVariant::Unsigned(2)
505            })
506        );
507
508        assert_eq!(
509            true,
510            Value::Number(Number {
511                inner: NumberVariant::Signed(3)
512            }) > Value::Number(Number {
513                inner: NumberVariant::Unsigned(2)
514            })
515        );
516
517        assert_eq!(
518            true,
519            Value::Number(Number {
520                inner: NumberVariant::Signed(2)
521            }) < Value::Number(Number {
522                inner: NumberVariant::Unsigned(3)
523            })
524        );
525
526        // signed with float
527        assert_eq!(
528            true,
529            Value::Number(Number {
530                inner: NumberVariant::Signed(2)
531            }) == Value::Number(Number {
532                inner: NumberVariant::Float(2.0)
533            })
534        );
535
536        assert_eq!(
537            true,
538            Value::Number(Number {
539                inner: NumberVariant::Signed(3)
540            }) > Value::Number(Number {
541                inner: NumberVariant::Float(2.0)
542            })
543        );
544
545        assert_eq!(
546            true,
547            Value::Number(Number {
548                inner: NumberVariant::Signed(2)
549            }) < Value::Number(Number {
550                inner: NumberVariant::Float(3.0)
551            })
552        );
553
554        // unsigned with float
555        assert_eq!(
556            true,
557            Value::Number(Number {
558                inner: NumberVariant::Unsigned(2)
559            }) == Value::Number(Number {
560                inner: NumberVariant::Float(2.0)
561            })
562        );
563
564        assert_eq!(
565            true,
566            Value::Number(Number {
567                inner: NumberVariant::Unsigned(3)
568            }) > Value::Number(Number {
569                inner: NumberVariant::Float(2.0)
570            })
571        );
572
573        assert_eq!(
574            true,
575            Value::Number(Number {
576                inner: NumberVariant::Unsigned(2)
577            }) < Value::Number(Number {
578                inner: NumberVariant::Float(3.0)
579            })
580        );
581
582        Ok(())
583    }
584
585    #[test]
586    fn debug_tests() -> anyhow::Result<()> {
587        assert_eq!(format!("{:?}", Value::Null), "Null".to_string());
588
589        assert_eq!(
590            format!("{:?}", Value::String("Richard Woolsey".to_string())),
591            "String(\"Richard Woolsey\")".to_string()
592        );
593
594        assert_eq!(
595            format!(
596                "{:?}",
597                Value::List(vec![
598                    Value::String("Aiden Ford".to_string()),
599                    Value::String("Rodney McKay".to_string()),
600                    Value::String("Ronon Dex".to_string())
601                ])
602            ),
603            "List [String(\"Aiden Ford\"), String(\"Rodney McKay\"), String(\"Ronon Dex\")]"
604                .to_string()
605        );
606
607        assert_eq!(
608            format!(
609                "{:?}",
610                Value::Number(Number {
611                    inner: NumberVariant::Unsigned(2)
612                })
613            ),
614            "Number(2)".to_string()
615        );
616
617        assert_eq!(
618            format!(
619                "{:?}",
620                Value::Number(Number {
621                    inner: NumberVariant::Signed(2)
622                })
623            ),
624            "Number(2)".to_string()
625        );
626
627        assert_eq!(
628            format!(
629                "{:?}",
630                Value::Number(Number {
631                    inner: NumberVariant::Float(2.0)
632                })
633            ),
634            "Number(2)".to_string()
635        );
636
637        Ok(())
638    }
639}