Skip to main content

litcheck_filecheck/expr/
value.rs

1use std::{borrow::Cow, convert::Infallible, fmt, str::FromStr};
2
3use crate::expr::{Expr, NumberFormat};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum Value<'a> {
7    Undef,
8    Str(Cow<'a, str>),
9    Num(Expr),
10}
11
12impl fmt::Display for Value<'_> {
13    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14        match self {
15            Self::Undef => Ok(()),
16            Self::Str(s) => f.write_str(s.as_ref()),
17            Self::Num(expr) => write!(f, "{expr}"),
18        }
19    }
20}
21
22impl FromStr for Value<'_> {
23    type Err = Infallible;
24
25    fn from_str(s: &str) -> Result<Self, Self::Err> {
26        if s.is_empty() {
27            Ok(Value::Str(Cow::Borrowed("")))
28        } else {
29            Ok(Value::Str(Cow::Owned(s.to_string())))
30        }
31    }
32}
33
34#[derive(Debug, Copy, Clone, PartialEq, Eq)]
35pub enum ValueType {
36    String,
37    Number(Option<NumberFormat>),
38}
39
40impl fmt::Display for ValueType {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        match self {
43            Self::String => f.write_str("string"),
44            Self::Number(None) => f.write_str("any number"),
45            Self::Number(Some(format)) => f.write_str(&format.describe()),
46        }
47    }
48}
49
50impl PartialOrd for ValueType {
51    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
52        Some(self.cmp(other))
53    }
54}
55
56impl Ord for ValueType {
57    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
58        use core::cmp::Ordering;
59        match (self, other) {
60            (Self::String, Self::String) => Ordering::Equal,
61            (Self::String, _) => Ordering::Less,
62            (_, Self::String) => Ordering::Greater,
63            (Self::Number(a), Self::Number(b)) => {
64                let a = a.unwrap_or_default();
65                let b = b.unwrap_or_default();
66                if a == b {
67                    Ordering::Equal
68                } else {
69                    let ap = a.precision();
70                    let bp = b.precision();
71                    if ap == 0 && bp > 0 {
72                        Ordering::Greater
73                    } else if ap > 0 && bp == 0 {
74                        Ordering::Less
75                    } else {
76                        ap.cmp(&bp)
77                            .then_with(|| a.discriminant().cmp(&b.discriminant()))
78                    }
79                }
80            }
81        }
82    }
83}