1use std::fmt;
11
12use serde::de::{Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
13
14#[derive(Debug, Clone, PartialEq, Default)]
16pub enum Json {
17 #[default]
19 Null,
20 Bool(bool),
22 Number(f64),
24 String(String),
26 Array(Vec<Json>),
28 Object(JsonObject),
30}
31
32#[derive(Debug, Clone, PartialEq, Default)]
34pub struct JsonObject {
35 entries: Vec<(String, Json)>,
36}
37
38fn is_array_index(key: &str) -> bool {
40 if key.is_empty() || key.len() > 10 || !key.bytes().all(|b| b.is_ascii_digit()) {
41 return false;
42 }
43 if key.len() > 1 && key.starts_with('0') {
44 return false;
45 }
46 key.parse::<u64>()
47 .map(|n| n < u64::from(u32::MAX))
48 .unwrap_or(false)
49}
50
51impl JsonObject {
52 pub fn new() -> Self {
54 Self::default()
55 }
56
57 pub fn insert(&mut self, key: impl Into<String>, value: impl Into<Json>) {
59 let key = key.into();
60 let value = value.into();
61 if let Some(slot) = self.entries.iter_mut().find(|(name, _)| *name == key) {
62 slot.1 = value;
63 return;
64 }
65 if is_array_index(&key) {
66 let number: u64 = key.parse().unwrap_or(0);
67 let at = self
68 .entries
69 .iter()
70 .position(|(name, _)| {
71 !is_array_index(name) || name.parse::<u64>().unwrap_or(0) > number
72 })
73 .unwrap_or(self.entries.len());
74 self.entries.insert(at, (key, value));
75 } else {
76 self.entries.push((key, value));
77 }
78 }
79
80 pub fn with(mut self, key: impl Into<String>, value: impl Into<Json>) -> Self {
82 self.insert(key, value);
83 self
84 }
85
86 pub fn extend_from(&mut self, other: &JsonObject) {
88 for (key, value) in &other.entries {
89 self.insert(key.clone(), value.clone());
90 }
91 }
92
93 pub fn get(&self, key: &str) -> Option<&Json> {
95 self.entries
96 .iter()
97 .find(|(name, _)| name == key)
98 .map(|(_, value)| value)
99 }
100
101 pub fn remove(&mut self, key: &str) -> Option<Json> {
103 let at = self.entries.iter().position(|(name, _)| name == key)?;
104 Some(self.entries.remove(at).1)
105 }
106
107 pub fn contains_key(&self, key: &str) -> bool {
109 self.get(key).is_some()
110 }
111
112 pub fn iter(&self) -> impl Iterator<Item = (&String, &Json)> {
114 self.entries.iter().map(|(key, value)| (key, value))
115 }
116
117 pub fn len(&self) -> usize {
119 self.entries.len()
120 }
121
122 pub fn is_empty(&self) -> bool {
124 self.entries.is_empty()
125 }
126}
127
128impl Json {
129 pub fn parse(text: &str) -> Result<Json, serde_json::Error> {
132 serde_json::from_str(text)
133 }
134
135 pub fn to_compact(&self) -> String {
137 let mut out = String::new();
138 write_value(&mut out, self, None, 0);
139 out
140 }
141
142 pub fn to_pretty(&self) -> String {
144 let mut out = String::new();
145 write_value(&mut out, self, Some(2), 0);
146 out
147 }
148
149 pub fn as_object(&self) -> Option<&JsonObject> {
151 match self {
152 Json::Object(object) => Some(object),
153 _ => None,
154 }
155 }
156
157 pub fn as_array(&self) -> Option<&Vec<Json>> {
159 match self {
160 Json::Array(items) => Some(items),
161 _ => None,
162 }
163 }
164
165 pub fn as_str(&self) -> Option<&str> {
167 match self {
168 Json::String(text) => Some(text),
169 _ => None,
170 }
171 }
172
173 pub fn as_f64(&self) -> Option<f64> {
175 match self {
176 Json::Number(number) => Some(*number),
177 _ => None,
178 }
179 }
180
181 pub fn get(&self, key: &str) -> Option<&Json> {
183 self.as_object().and_then(|object| object.get(key))
184 }
185
186 pub fn is_null(&self) -> bool {
188 matches!(self, Json::Null)
189 }
190
191 pub fn truthy(&self) -> bool {
193 match self {
194 Json::Null => false,
195 Json::Bool(value) => *value,
196 Json::Number(number) => *number != 0.0 && !number.is_nan(),
197 Json::String(text) => !text.is_empty(),
198 Json::Array(_) | Json::Object(_) => true,
199 }
200 }
201
202 pub fn to_value(&self) -> serde_json::Value {
205 match self {
206 Json::Null => serde_json::Value::Null,
207 Json::Bool(value) => serde_json::Value::Bool(*value),
208 Json::Number(number) => {
209 if number.fract() == 0.0 && number.abs() < 9_007_199_254_740_992.0 {
210 serde_json::Value::from(*number as i64)
211 } else {
212 serde_json::Number::from_f64(*number)
213 .map(serde_json::Value::Number)
214 .unwrap_or(serde_json::Value::Null)
215 }
216 }
217 Json::String(text) => serde_json::Value::String(text.clone()),
218 Json::Array(items) => {
219 serde_json::Value::Array(items.iter().map(Json::to_value).collect())
220 }
221 Json::Object(object) => serde_json::Value::Object(
222 object
223 .iter()
224 .map(|(key, value)| (key.clone(), value.to_value()))
225 .collect(),
226 ),
227 }
228 }
229}
230
231pub fn js_string(value: Option<&Json>) -> String {
233 match value {
234 None => "undefined".to_string(),
235 Some(Json::Null) => "null".to_string(),
236 Some(Json::Bool(value)) => value.to_string(),
237 Some(Json::Number(number)) => js_number(*number),
238 Some(Json::String(text)) => text.clone(),
239 Some(Json::Array(items)) => items
240 .iter()
241 .map(|item| match item {
242 Json::Null => String::new(),
243 other => js_string(Some(other)),
244 })
245 .collect::<Vec<_>>()
246 .join(","),
247 Some(Json::Object(_)) => "[object Object]".to_string(),
248 }
249}
250
251pub fn js_strict_equal(left: Option<&Json>, right: Option<&Json>) -> bool {
254 match (left, right) {
255 (None, None) => true,
256 (Some(Json::Null), Some(Json::Null)) => true,
257 (Some(Json::Bool(a)), Some(Json::Bool(b))) => a == b,
258 (Some(Json::Number(a)), Some(Json::Number(b))) => a == b,
259 (Some(Json::String(a)), Some(Json::String(b))) => a == b,
260 _ => false,
261 }
262}
263
264pub fn utf16_len(text: &str) -> usize {
266 text.encode_utf16().count()
267}
268
269pub fn js_number(number: f64) -> String {
271 if number.is_nan() {
272 return "NaN".to_string();
273 }
274 if number.is_infinite() {
275 return if number > 0.0 {
276 "Infinity"
277 } else {
278 "-Infinity"
279 }
280 .to_string();
281 }
282 if number == 0.0 {
283 return "0".to_string();
284 }
285 let sign = if number < 0.0 { "-" } else { "" };
286 let formatted = format!("{:e}", number.abs());
288 let (mantissa, exponent) = formatted.split_once('e').unwrap_or((&formatted, "0"));
289 let digits: String = mantissa.chars().filter(|c| *c != '.').collect();
290 let exponent: i64 = exponent.parse().unwrap_or(0);
291 let k = digits.len() as i64;
292 let n = exponent + 1;
293
294 let body = if k <= n && n <= 21 {
295 format!("{digits}{}", "0".repeat((n - k) as usize))
296 } else if 0 < n && n <= 21 {
297 let (whole, fraction) = digits.split_at(n as usize);
298 format!("{whole}.{fraction}")
299 } else if -6 < n && n <= 0 {
300 format!("0.{}{digits}", "0".repeat((-n) as usize))
301 } else {
302 let e = n - 1;
303 let e_sign = if e < 0 { '-' } else { '+' };
304 if k == 1 {
305 format!("{digits}e{e_sign}{}", e.abs())
306 } else {
307 let (first, rest) = digits.split_at(1);
308 format!("{first}.{rest}e{e_sign}{}", e.abs())
309 }
310 };
311 format!("{sign}{body}")
312}
313
314fn write_string(out: &mut String, text: &str) {
315 out.push('"');
316 for c in text.chars() {
317 match c {
318 '"' => out.push_str("\\\""),
319 '\\' => out.push_str("\\\\"),
320 '\u{8}' => out.push_str("\\b"),
321 '\u{c}' => out.push_str("\\f"),
322 '\n' => out.push_str("\\n"),
323 '\r' => out.push_str("\\r"),
324 '\t' => out.push_str("\\t"),
325 c if (c as u32) < 0x20 => out.push_str(&format!("\\u{:04x}", c as u32)),
326 c => out.push(c),
327 }
328 }
329 out.push('"');
330}
331
332fn newline(out: &mut String, indent: Option<usize>, depth: usize) {
333 if let Some(width) = indent {
334 out.push('\n');
335 out.push_str(&" ".repeat(width * depth));
336 }
337}
338
339fn write_value(out: &mut String, value: &Json, indent: Option<usize>, depth: usize) {
340 match value {
341 Json::Null => out.push_str("null"),
342 Json::Bool(value) => out.push_str(if *value { "true" } else { "false" }),
343 Json::Number(number) => {
344 if number.is_finite() {
345 out.push_str(&js_number(*number));
346 } else {
347 out.push_str("null");
348 }
349 }
350 Json::String(text) => write_string(out, text),
351 Json::Array(items) => {
352 if items.is_empty() {
353 out.push_str("[]");
354 return;
355 }
356 out.push('[');
357 for (at, item) in items.iter().enumerate() {
358 if at > 0 {
359 out.push(',');
360 }
361 newline(out, indent, depth + 1);
362 write_value(out, item, indent, depth + 1);
363 }
364 newline(out, indent, depth);
365 out.push(']');
366 }
367 Json::Object(object) => {
368 if object.is_empty() {
369 out.push_str("{}");
370 return;
371 }
372 out.push('{');
373 for (at, (key, item)) in object.iter().enumerate() {
374 if at > 0 {
375 out.push(',');
376 }
377 newline(out, indent, depth + 1);
378 write_string(out, key);
379 out.push(':');
380 if indent.is_some() {
381 out.push(' ');
382 }
383 write_value(out, item, indent, depth + 1);
384 }
385 newline(out, indent, depth);
386 out.push('}');
387 }
388 }
389}
390
391impl fmt::Display for Json {
392 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393 f.write_str(&self.to_compact())
394 }
395}
396
397struct JsonVisitor;
398
399impl<'de> Visitor<'de> for JsonVisitor {
400 type Value = Json;
401
402 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
403 f.write_str("any JSON value")
404 }
405
406 fn visit_bool<E>(self, value: bool) -> Result<Json, E> {
407 Ok(Json::Bool(value))
408 }
409
410 fn visit_i64<E>(self, value: i64) -> Result<Json, E> {
411 Ok(Json::Number(value as f64))
412 }
413
414 fn visit_u64<E>(self, value: u64) -> Result<Json, E> {
415 Ok(Json::Number(value as f64))
416 }
417
418 fn visit_f64<E>(self, value: f64) -> Result<Json, E> {
419 Ok(Json::Number(value))
420 }
421
422 fn visit_str<E>(self, value: &str) -> Result<Json, E> {
423 Ok(Json::String(value.to_string()))
424 }
425
426 fn visit_string<E>(self, value: String) -> Result<Json, E> {
427 Ok(Json::String(value))
428 }
429
430 fn visit_unit<E>(self) -> Result<Json, E> {
431 Ok(Json::Null)
432 }
433
434 fn visit_none<E>(self) -> Result<Json, E> {
435 Ok(Json::Null)
436 }
437
438 fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> Result<Json, D::Error> {
439 Deserialize::deserialize(deserializer)
440 }
441
442 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Json, A::Error> {
443 let mut items = Vec::new();
444 while let Some(item) = seq.next_element()? {
445 items.push(item);
446 }
447 Ok(Json::Array(items))
448 }
449
450 fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Json, A::Error> {
451 let mut object = JsonObject::new();
452 while let Some((key, value)) = map.next_entry::<String, Json>()? {
453 object.insert(key, value);
454 }
455 Ok(Json::Object(object))
456 }
457}
458
459impl<'de> Deserialize<'de> for Json {
460 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Json, D::Error> {
461 deserializer.deserialize_any(JsonVisitor)
462 }
463}
464
465impl From<&serde_json::Value> for Json {
466 fn from(value: &serde_json::Value) -> Self {
467 match value {
468 serde_json::Value::Null => Json::Null,
469 serde_json::Value::Bool(value) => Json::Bool(*value),
470 serde_json::Value::Number(number) => Json::Number(number.as_f64().unwrap_or(f64::NAN)),
471 serde_json::Value::String(text) => Json::String(text.clone()),
472 serde_json::Value::Array(items) => Json::Array(items.iter().map(Json::from).collect()),
473 serde_json::Value::Object(map) => {
474 let mut object = JsonObject::new();
475 for (key, item) in map {
476 object.insert(key.clone(), Json::from(item));
477 }
478 Json::Object(object)
479 }
480 }
481 }
482}
483
484impl From<serde_json::Value> for Json {
485 fn from(value: serde_json::Value) -> Self {
486 Json::from(&value)
487 }
488}
489
490impl From<&str> for Json {
491 fn from(value: &str) -> Self {
492 Json::String(value.to_string())
493 }
494}
495
496impl From<String> for Json {
497 fn from(value: String) -> Self {
498 Json::String(value)
499 }
500}
501
502impl From<&String> for Json {
503 fn from(value: &String) -> Self {
504 Json::String(value.clone())
505 }
506}
507
508impl From<bool> for Json {
509 fn from(value: bool) -> Self {
510 Json::Bool(value)
511 }
512}
513
514impl From<f64> for Json {
515 fn from(value: f64) -> Self {
516 Json::Number(value)
517 }
518}
519
520macro_rules! json_from_integer {
521 ($($kind:ty),*) => {
522 $(impl From<$kind> for Json {
523 fn from(value: $kind) -> Self {
524 Json::Number(value as f64)
525 }
526 })*
527 };
528}
529
530json_from_integer!(i32, i64, u32, u64, usize);
531
532impl From<JsonObject> for Json {
533 fn from(value: JsonObject) -> Self {
534 Json::Object(value)
535 }
536}
537
538impl From<Vec<Json>> for Json {
539 fn from(value: Vec<Json>) -> Self {
540 Json::Array(value)
541 }
542}
543
544impl<T: Into<Json>> From<Option<T>> for Json {
545 fn from(value: Option<T>) -> Self {
546 value.map(Into::into).unwrap_or(Json::Null)
547 }
548}
549
550impl FromIterator<(String, Json)> for JsonObject {
551 fn from_iter<I: IntoIterator<Item = (String, Json)>>(iter: I) -> Self {
552 let mut object = JsonObject::new();
553 for (key, value) in iter {
554 object.insert(key, value);
555 }
556 object
557 }
558}
559
560#[cfg(test)]
561mod tests {
562 use super::*;
563
564 #[test]
565 fn numbers_print_like_javascript() {
566 let cases = [
567 (0.0, "0"),
568 (-0.0, "0"),
569 (1.0, "1"),
570 (2.0, "2"),
571 (0.25, "0.25"),
572 (1234.5, "1234.5"),
573 (1e21, "1e+21"),
574 (1.5e21, "1.5e+21"),
575 (123e18, "123000000000000000000"),
576 (1e-7, "1e-7"),
577 (1.25e-7, "1.25e-7"),
578 (0.000001, "0.000001"),
579 (0.1 + 0.2, "0.30000000000000004"),
580 (-42.0, "-42"),
581 (1767225600000.0, "1767225600000"),
582 ];
583 for (number, expected) in cases {
584 assert_eq!(js_number(number), expected, "{number}");
585 }
586 }
587
588 #[test]
589 fn objects_keep_javascript_key_order() {
590 let parsed = Json::parse(r#"{"b":1,"a":2,"10":3,"2":4,"b":5,"01":6}"#).unwrap();
591 assert_eq!(parsed.to_compact(), r#"{"2":4,"10":3,"b":5,"a":2,"01":6}"#);
592 }
593
594 #[test]
595 fn strings_escape_like_json_stringify() {
596 let value = Json::from("a\"b\\c\n\u{1}\u{2028}✓");
597 assert_eq!(value.to_compact(), "\"a\\\"b\\\\c\\n\\u0001\u{2028}✓\"");
598 }
599
600 #[test]
601 fn pretty_output_matches_json_stringify_with_two_spaces() {
602 let value = Json::parse(r#"{"a":[1,{"b":[]}],"c":{}}"#).unwrap();
603 assert_eq!(
604 value.to_pretty(),
605 "{\n \"a\": [\n 1,\n {\n \"b\": []\n }\n ],\n \"c\": {}\n}"
606 );
607 }
608}