1use std::cmp::Ordering;
13
14#[derive(Debug, Clone)]
15pub enum Value {
16 Null,
17 Bool(bool),
18 Int(i64),
19 Float(f64),
20 Str(String),
21 Array(Vec<Value>),
22 Object(Vec<(String, Value)>),
23}
24
25impl PartialEq for Value {
28 fn eq(&self, other: &Value) -> bool {
29 self.value_eq(other)
30 }
31}
32
33impl Value {
34 pub fn is_truthy(&self) -> bool {
36 !matches!(self, Value::Null | Value::Bool(false))
37 }
38
39 pub fn type_name(&self) -> &'static str {
41 match self {
42 Value::Null => "null",
43 Value::Bool(_) => "boolean",
44 Value::Int(_) | Value::Float(_) => "number",
45 Value::Str(_) => "string",
46 Value::Array(_) => "array",
47 Value::Object(_) => "object",
48 }
49 }
50
51 pub fn as_f64(&self) -> Option<f64> {
53 match self {
54 Value::Int(i) => Some(*i as f64),
55 Value::Float(f) => Some(*f),
56 _ => None,
57 }
58 }
59
60 pub fn order(&self, other: &Value) -> Ordering {
63 fn rank(v: &Value) -> u8 {
64 match v {
65 Value::Null => 0,
66 Value::Bool(_) => 1,
67 Value::Int(_) | Value::Float(_) => 2,
68 Value::Str(_) => 3,
69 Value::Array(_) => 4,
70 Value::Object(_) => 5,
71 }
72 }
73 match (self, other) {
74 (Value::Null, Value::Null) => Ordering::Equal,
75 (Value::Bool(a), Value::Bool(b)) => a.cmp(b),
76 (Value::Str(a), Value::Str(b)) => a.cmp(b),
77 (Value::Array(a), Value::Array(b)) => {
78 for (x, y) in a.iter().zip(b.iter()) {
79 let c = x.order(y);
80 if c != Ordering::Equal {
81 return c;
82 }
83 }
84 a.len().cmp(&b.len())
85 }
86 (Value::Object(a), Value::Object(b)) => {
87 let mut ka: Vec<&String> = a.iter().map(|(k, _)| k).collect();
89 let mut kb: Vec<&String> = b.iter().map(|(k, _)| k).collect();
90 ka.sort();
91 kb.sort();
92 match ka.cmp(&kb) {
93 Ordering::Equal => {}
94 ne => return ne,
95 }
96 for k in ka {
97 let va = a.iter().find(|(kk, _)| kk == k).map(|(_, v)| v);
98 let vb = b.iter().find(|(kk, _)| kk == k).map(|(_, v)| v);
99 if let (Some(va), Some(vb)) = (va, vb) {
100 let c = va.order(vb);
101 if c != Ordering::Equal {
102 return c;
103 }
104 }
105 }
106 Ordering::Equal
107 }
108 _ => {
109 if let (Some(a), Some(b)) = (self.as_f64(), other.as_f64()) {
111 a.partial_cmp(&b).unwrap_or(Ordering::Equal)
112 } else {
113 rank(self).cmp(&rank(other))
114 }
115 }
116 }
117 }
118
119 pub fn value_eq(&self, other: &Value) -> bool {
121 self.order(other) == Ordering::Equal
122 }
123
124 pub fn to_raw_string(&self) -> String {
127 match self {
128 Value::Str(s) => s.clone(),
129 Value::Null => "null".to_string(),
130 Value::Bool(b) => b.to_string(),
131 Value::Int(i) => i.to_string(),
132 Value::Float(f) => format_f64(*f),
133 Value::Array(_) | Value::Object(_) => self.to_json5(),
134 }
135 }
136
137 pub fn to_json(&self) -> String {
139 let mut out = String::new();
140 self.write_json_inner(&mut out, false);
141 out
142 }
143
144 pub fn to_json5(&self) -> String {
151 let mut out = String::new();
152 self.write_json_inner(&mut out, true);
153 out
154 }
155
156 fn write_json_inner(&self, out: &mut String, json5: bool) {
157 match self {
158 Value::Null => out.push_str("null"),
159 Value::Bool(b) => out.push_str(if *b { "true" } else { "false" }),
160 Value::Int(i) => out.push_str(&i.to_string()),
161 Value::Float(f) if !f.is_finite() && json5 => out.push_str(&format_f64(*f)),
166 Value::Float(f) if !f.is_finite() => out.push_str("null"),
167 Value::Float(f) => out.push_str(&format_f64(*f)),
168 Value::Str(s) => write_json_string(s, out),
169 Value::Array(a) => {
170 out.push('[');
171 for (i, v) in a.iter().enumerate() {
172 if i > 0 {
173 out.push(',');
174 }
175 v.write_json_inner(out, json5);
176 }
177 out.push(']');
178 }
179 Value::Object(m) => {
180 out.push('{');
181 for (i, (k, v)) in m.iter().enumerate() {
182 if i > 0 {
183 out.push(',');
184 }
185 write_json_string(k, out);
186 out.push(':');
187 v.write_json_inner(out, json5);
188 }
189 out.push('}');
190 }
191 }
192 }
193}
194
195impl From<bool> for Value {
196 fn from(input: bool) -> Self {
197 Self::Bool(input)
198 }
199}
200
201macro_rules! from_int {
202 ($($t:ty),+) => {$(
203 impl From<$t> for Value {
204 fn from(input: $t) -> Self {
205 Self::Int(input as i64)
206 }
207 }
208 )+};
209}
210from_int!(i8, i16, i32, i64, u8, u16, u32, isize);
214
215macro_rules! from_float {
216 ($($t:ty),+) => {$(
217 impl From<$t> for Value {
218 fn from(input: $t) -> Self {
219 Self::Float(input as f64)
220 }
221 }
222 )+};
223}
224from_float!(f32, f64);
225
226impl<T: Into<Value>> From<Option<T>> for Value {
228 fn from(input: Option<T>) -> Self {
229 input.map_or(Self::Null, Into::into)
230 }
231}
232
233impl<T: Into<Value>> From<Vec<T>> for Value {
234 fn from(input: Vec<T>) -> Self {
235 Self::Array(input.into_iter().map(Into::into).collect())
236 }
237}
238
239impl<T: Into<Value> + Clone> From<&[T]> for Value {
240 fn from(input: &[T]) -> Self {
241 Self::Array(input.iter().cloned().map(Into::into).collect())
242 }
243}
244
245impl<K: Into<String>, V: Into<Value>> FromIterator<(K, V)> for Value {
246 fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
248 Self::Object(
249 iter.into_iter()
250 .map(|(k, v)| (k.into(), v.into()))
251 .collect(),
252 )
253 }
254}
255
256impl From<&str> for Value {
257 fn from(input: &str) -> Self {
258 Self::Str(input.to_string())
259 }
260}
261
262impl From<String> for Value {
263 fn from(input: String) -> Self {
264 Self::Str(input)
265 }
266}
267
268fn format_f64(f: f64) -> String {
275 if f.is_nan() {
276 return "NaN".to_string();
277 }
278 if f.is_infinite() {
279 return if f > 0.0 { "Infinity" } else { "-Infinity" }.to_string();
280 }
281 if f.fract() == 0.0 && f.abs() < 1e15 {
282 format!("{}", f as i64)
283 } else {
284 format!("{f}")
285 }
286}
287
288fn write_json_string(s: &str, out: &mut String) {
289 out.push('"');
290 for c in s.chars() {
291 match c {
292 '"' => out.push_str("\\\""),
293 '\\' => out.push_str("\\\\"),
294 '\n' => out.push_str("\\n"),
295 '\r' => out.push_str("\\r"),
296 '\t' => out.push_str("\\t"),
297 c if (c as u32) < 0x20 => out.push_str(&format!("\\u{:04x}", c as u32)),
298 c => out.push(c),
299 }
300 }
301 out.push('"');
302}
303
304#[cfg(test)]
305mod tests {
306 use super::*;
307
308 fn arr(v: &[Value]) -> Value {
309 Value::Array(v.to_vec())
310 }
311 fn obj(pairs: &[(&str, Value)]) -> Value {
312 Value::Object(
313 pairs
314 .iter()
315 .map(|(k, v)| (k.to_string(), v.clone()))
316 .collect(),
317 )
318 }
319
320 #[test]
321 fn total_order_across_types() {
322 let ladder = [
324 Value::Null,
325 Value::Bool(false),
326 Value::Bool(true),
327 Value::Int(-1),
328 Value::Float(2.5),
329 Value::Str("a".into()),
330 arr(&[Value::Int(1)]),
331 obj(&[("k", Value::Int(1))]),
332 ];
333 for i in 0..ladder.len() {
334 for j in 0..ladder.len() {
335 let want = i.cmp(&j);
336 if want != Ordering::Equal {
339 assert_eq!(
340 ladder[i].order(&ladder[j]),
341 want,
342 "{:?} vs {:?}",
343 ladder[i],
344 ladder[j]
345 );
346 }
347 }
348 }
349 }
350
351 #[test]
352 fn numbers_compare_across_int_and_float() {
353 assert!(Value::Int(1).value_eq(&Value::Float(1.0)));
354 assert_eq!(Value::Int(2).order(&Value::Float(2.5)), Ordering::Less);
355 assert_eq!(Value::Float(3.0).order(&Value::Int(3)), Ordering::Equal);
356 assert_eq!(Value::Int(1).as_f64(), Some(1.0));
357 assert_eq!(Value::Str("x".into()).as_f64(), None);
358 }
359
360 #[test]
361 fn arrays_and_objects_order_structurally() {
362 assert_eq!(
364 arr(&[Value::Int(1), Value::Int(2)]).order(&arr(&[Value::Int(1), Value::Int(3)])),
365 Ordering::Less
366 );
367 assert_eq!(
368 arr(&[Value::Int(1)]).order(&arr(&[Value::Int(1), Value::Int(0)])),
369 Ordering::Less
370 );
371 assert_eq!(
373 obj(&[("a", Value::Int(1))]).order(&obj(&[("b", Value::Int(1))])),
374 Ordering::Less
375 );
376 assert_eq!(
377 obj(&[("a", Value::Int(1))]).order(&obj(&[("a", Value::Int(2))])),
378 Ordering::Less
379 );
380 assert!(
382 obj(&[("a", Value::Int(1)), ("b", Value::Int(2))])
383 .value_eq(&obj(&[("b", Value::Int(2)), ("a", Value::Int(1))]))
384 );
385 }
386
387 #[test]
388 fn non_finite_floats_use_the_json5_spelling_but_encode_as_json_null() {
389 assert_eq!(Value::Float(f64::INFINITY).to_raw_string(), "Infinity");
391 assert_eq!(Value::Float(f64::NEG_INFINITY).to_raw_string(), "-Infinity");
392 assert_eq!(Value::Float(f64::NAN).to_raw_string(), "NaN");
393 assert_eq!(Value::Float(f64::INFINITY).to_json(), "null");
396 assert_eq!(Value::Float(f64::NAN).to_json(), "null");
397 assert_eq!(
398 obj(&[("a", Value::Float(f64::NEG_INFINITY))]).to_json(),
399 "{\"a\":null}"
400 );
401 assert_eq!(Value::Float(f64::INFINITY).to_json5(), "Infinity");
405 assert_eq!(Value::Float(f64::NEG_INFINITY).to_json5(), "-Infinity");
406 assert_eq!(Value::Float(f64::NAN).to_json5(), "NaN");
407 assert_eq!(
408 arr(&[Value::Float(f64::INFINITY), Value::Float(f64::NAN)]).to_json5(),
409 "[Infinity,NaN]"
410 );
411 assert_eq!(
412 obj(&[("n", Value::Float(f64::NEG_INFINITY))]).to_json5(),
413 "{\"n\":-Infinity}"
414 );
415 assert_eq!(
416 obj(&[("a", Value::Array(vec![Value::Float(f64::INFINITY)]))]).to_json(),
417 "{\"a\":[null]}"
418 );
419 assert_eq!(Value::Float(1e14).to_json(), "100000000000000");
421 assert_eq!(arr(&[Value::Float(1.5)]).to_json(), "[1.5]");
422 assert_eq!(arr(&[Value::Float(1.5)]).to_json5(), "[1.5]");
423 }
424
425 #[test]
426 fn raw_string_and_truthiness() {
427 assert_eq!(Value::Float(1.0).to_raw_string(), "1");
428 assert_eq!(Value::Float(1.5).to_raw_string(), "1.5");
429 assert_eq!(Value::Null.to_raw_string(), "null");
430 assert_eq!(Value::Bool(true).to_raw_string(), "true");
431 assert_eq!(arr(&[Value::Int(1)]).to_raw_string(), "[1]");
432 assert_eq!(obj(&[("a", Value::Int(1))]).to_raw_string(), "{\"a\":1}");
433 assert!(Value::Int(0).is_truthy());
435 assert!(Value::Str("".into()).is_truthy());
436 assert!(!Value::Bool(false).is_truthy());
437 assert!(!Value::Null.is_truthy());
438 }
439
440 #[test]
441 fn json_encoding_escapes_and_floats() {
442 assert_eq!(
443 Value::Str("a\"b\\c\n\t\r".into()).to_json(),
444 "\"a\\\"b\\\\c\\n\\t\\r\""
445 );
446 assert_eq!(Value::Str("\u{0001}".into()).to_json(), "\"\\u0001\"");
448 assert_eq!(Value::Float(42.0).to_json(), "42");
450 assert_eq!(Value::Float(2.5).to_json(), "2.5");
451 assert_eq!(
452 obj(&[("n", Value::Null), ("xs", arr(&[Value::Bool(true)]))]).to_json(),
453 "{\"n\":null,\"xs\":[true]}"
454 );
455 assert_eq!(arr(&[]).to_json(), "[]");
456 }
457
458 #[test]
459 fn type_names() {
460 assert_eq!(Value::Null.type_name(), "null");
461 assert_eq!(Value::Bool(true).type_name(), "boolean");
462 assert_eq!(Value::Int(1).type_name(), "number");
463 assert_eq!(Value::Float(1.0).type_name(), "number");
464 assert_eq!(Value::Str("x".into()).type_name(), "string");
465 assert_eq!(arr(&[]).type_name(), "array");
466 assert_eq!(obj(&[]).type_name(), "object");
467 }
468}