1use std::collections::BTreeMap;
7
8#[derive(Debug, Clone, PartialEq)]
15pub enum Value {
16 Null,
17 Bool(bool),
18 Int(i64),
19 Float(f64),
20 Str(String),
21 List(Vec<Value>),
22 Map(BTreeMap<String, Value>),
23}
24
25impl Value {
26 pub fn type_name(&self) -> &'static str {
27 match self {
28 Value::Null => "null",
29 Value::Bool(_) => "bool",
30 Value::Int(_) => "int",
31 Value::Float(_) => "float",
32 Value::Str(_) => "string",
33 Value::List(_) => "list",
34 Value::Map(_) => "map",
35 }
36 }
37
38 pub fn matches_type(&self, ty: &str) -> bool {
41 match (self, ty) {
42 (Value::Null, _) => true,
43 (Value::Bool(_), "bool") => true,
44 (Value::Int(_), "int") => true,
45 (Value::Float(_), "float") => true,
46 (Value::Str(_), "string") => true,
47 (Value::List(_), "list") => true,
48 (Value::Map(_), "map") => true,
49 _ => false,
50 }
51 }
52
53 pub fn as_bool(&self) -> Option<bool> {
54 match self {
55 Value::Bool(b) => Some(*b),
56 _ => None,
57 }
58 }
59
60 pub fn truthy(&self) -> bool {
61 match self {
62 Value::Bool(b) => *b,
63 Value::Null => false,
64 Value::Int(i) => *i != 0,
65 Value::Float(f) => *f != 0.0,
66 Value::Str(s) => !s.is_empty(),
67 Value::List(l) => !l.is_empty(),
68 Value::Map(m) => !m.is_empty(),
69 }
70 }
71
72 pub fn as_str_value(&self) -> Option<&str> {
73 match self {
74 Value::Str(s) => Some(s.as_str()),
75 _ => None,
76 }
77 }
78
79 pub fn coerce_to(&self, ty: &str) -> Option<Value> {
82 match (self, ty) {
83 (Value::Null, _) => Some(Value::Null),
84 (Value::Bool(b), "bool") => Some(Value::Bool(*b)),
85 (Value::Int(i), "int") => Some(Value::Int(*i)),
86 (Value::Float(f), "float") => Some(Value::Float(*f)),
87 (Value::Str(s), "string") => Some(Value::Str(s.clone())),
88 (Value::List(l), "list") => Some(Value::List(l.clone())),
89 (Value::Map(m), "map") => Some(Value::Map(m.clone())),
90 (Value::Int(i), "float") => Some(Value::Float(*i as f64)),
92 _ => None,
94 }
95 }
96}
97
98impl serde::Serialize for Value {
101 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
102 self.to_json().serialize(s)
103 }
104}
105
106impl<'de> serde::Deserialize<'de> for Value {
107 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
108 serde_json::Value::deserialize(d).map(|j| Value::from_json(&j))
109 }
110}
111
112impl Value {
113 pub fn from_yaml(v: &serde_yaml::Value) -> Value {
114 use serde_yaml::Value::*;
115 match v {
116 Null => Value::Null,
117 Bool(b) => Value::Bool(*b),
118 Number(n) => {
119 if let Some(i) = n.as_i64() {
120 Value::Int(i)
121 } else if let Some(u) = n.as_u64() {
122 Value::Int(u as i64)
123 } else {
124 Value::Float(n.as_f64().unwrap_or(f64::NAN))
125 }
126 }
127 String(s) => Value::Str(s.clone()),
128 Sequence(seq) => Value::List(seq.iter().map(Value::from_yaml).collect()),
129 Mapping(m) => {
130 let mut map = BTreeMap::new();
131 for (k, v) in m {
132 let key = match k {
133 String(s) => s.clone(),
134 Bool(b) => b.to_string(),
135 Number(n) => n.to_string(),
136 Null => "null".to_string(),
137 _ => continue,
138 };
139 map.insert(key, Value::from_yaml(v));
140 }
141 Value::Map(map)
142 }
143 Tagged(t) => Value::from_yaml(&t.value),
144 }
145 }
146
147 pub fn to_json(&self) -> serde_json::Value {
148 match self {
149 Value::Null => serde_json::Value::Null,
150 Value::Bool(b) => serde_json::Value::Bool(*b),
151 Value::Int(i) => serde_json::Value::Number((*i as i64).into()),
152 Value::Float(f) => serde_json::Number::from_f64(*f)
153 .map(serde_json::Value::Number)
154 .unwrap_or(serde_json::Value::Null),
155 Value::Str(s) => serde_json::Value::String(s.clone()),
156 Value::List(l) => serde_json::Value::Array(l.iter().map(Value::to_json).collect()),
157 Value::Map(m) => {
158 let mut o = serde_json::Map::new();
159 for (k, v) in m {
160 o.insert(k.clone(), v.to_json());
161 }
162 serde_json::Value::Object(o)
163 }
164 }
165 }
166
167 pub fn from_json(v: &serde_json::Value) -> Value {
168 match v {
169 serde_json::Value::Null => Value::Null,
170 serde_json::Value::Bool(b) => Value::Bool(*b),
171 serde_json::Value::Number(n) => {
172 if let Some(i) = n.as_i64() {
173 Value::Int(i)
174 } else if let Some(u) = n.as_u64() {
175 Value::Int(u as i64)
176 } else {
177 Value::Float(n.as_f64().unwrap_or(f64::NAN))
178 }
179 }
180 serde_json::Value::String(s) => Value::Str(s.clone()),
181 serde_json::Value::Array(a) => {
182 Value::List(a.iter().map(Value::from_json).collect())
183 }
184 serde_json::Value::Object(o) => {
185 let mut m = BTreeMap::new();
186 for (k, v) in o {
187 m.insert(k.clone(), Value::from_json(v));
188 }
189 Value::Map(m)
190 }
191 }
192 }
193}
194
195pub fn map1(k: &str, v: Value) -> Value {
197 let mut m = BTreeMap::new();
198 m.insert(k.to_string(), v);
199 Value::Map(m)
200}