Skip to main content

sqruff_lib_core/
value.rs

1use std::ops::Index;
2use std::str::FromStr;
3
4use hashbrown::HashMap;
5use itertools::Itertools;
6
7#[derive(Debug, Clone, PartialEq, Default)]
8#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
9#[cfg_attr(feature = "serde", serde(untagged))]
10pub enum Value {
11    Int(i32),
12    Bool(bool),
13    Float(f64),
14    String(Box<str>),
15    Map(HashMap<String, Value>),
16    Array(Vec<Value>),
17    #[default]
18    None,
19}
20
21impl Value {
22    pub fn is_none(&self) -> bool {
23        matches!(self, Value::None)
24    }
25
26    pub fn as_array(&self) -> Option<Vec<Value>> {
27        match self {
28            Self::Array(v) => Some(v.clone()),
29            Self::String(q) => {
30                let xs = q
31                    .split(',')
32                    .map(|it| Value::String(it.into()))
33                    .collect_vec();
34                Some(xs)
35            }
36            Self::Bool(b) => Some(vec![Value::String(b.to_string().into())]),
37            _ => None,
38        }
39    }
40}
41
42impl Index<&str> for Value {
43    type Output = Value;
44
45    fn index(&self, index: &str) -> &Self::Output {
46        match self {
47            Value::Map(map) => map.get(index).unwrap_or(&Value::None),
48            _ => unreachable!(),
49        }
50    }
51}
52
53impl Value {
54    pub fn to_bool(&self) -> bool {
55        match *self {
56            Value::Int(v) => v != 0,
57            Value::Bool(v) => v,
58            Value::Float(v) => v != 0.0,
59            Value::String(ref v) => !v.is_empty(),
60            Value::Map(ref v) => !v.is_empty(),
61            Value::None => false,
62            Value::Array(ref v) => !v.is_empty(),
63        }
64    }
65
66    pub fn map<T>(&self, f: impl Fn(&Self) -> T) -> Option<T> {
67        if self == &Value::None {
68            return None;
69        }
70
71        Some(f(self))
72    }
73
74    pub fn as_map(&self) -> Option<&HashMap<String, Value>> {
75        if let Self::Map(map) = self {
76            Some(map)
77        } else {
78            None
79        }
80    }
81
82    pub fn as_map_mut(&mut self) -> Option<&mut HashMap<String, Value>> {
83        if let Self::Map(map) = self {
84            Some(map)
85        } else {
86            None
87        }
88    }
89
90    pub fn as_int(&self) -> Option<i32> {
91        if let Self::Int(v) = self {
92            Some(*v)
93        } else {
94            None
95        }
96    }
97
98    pub fn as_string(&self) -> Option<&str> {
99        if let Self::String(v) = self {
100            Some(v)
101        } else {
102            None
103        }
104    }
105
106    pub fn as_bool(&self) -> Option<bool> {
107        if let Self::Bool(v) = self {
108            Some(*v)
109        } else {
110            None
111        }
112    }
113}
114
115impl FromStr for Value {
116    type Err = ();
117
118    fn from_str(s: &str) -> Result<Self, Self::Err> {
119        if let Ok(value) = s.parse() {
120            return Ok(Value::Int(value));
121        }
122
123        if let Ok(value) = s.parse() {
124            return Ok(Value::Float(value));
125        }
126
127        let value = match () {
128            _ if s.eq_ignore_ascii_case("true") => Value::Bool(true),
129            _ if s.eq_ignore_ascii_case("false") => Value::Bool(false),
130            _ if s.eq_ignore_ascii_case("none") => Value::None,
131            _ => Value::String(Box::from(s)),
132        };
133
134        Ok(value)
135    }
136}