1pub mod literal;
2pub mod string;
3pub mod validation;
4
5use indexmap::IndexMap;
6pub use literal::{
7 is_keyword,
8 is_literal_like,
9 is_numeric_like,
10 is_structural_char,
11};
12pub use string::{
13 escape_string,
14 is_valid_unquoted_key,
15 needs_quoting,
16 quote_string,
17 unescape_string,
18};
19
20use crate::types::{
21 JsonValue as Value,
22 Number,
23};
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum QuotingContext {
28 ObjectValue,
29 ArrayValue,
30}
31
32pub fn normalize(value: Value) -> Value {
34 match value {
35 Value::Number(n) => {
36 if let Number::NegInt(0) = n {
38 Value::Number(Number::from(0u64))
39 } else if let Some(f) = n.as_f64() {
40 if f.is_nan() || f.is_infinite() {
41 Value::Null
42 } else if f == 0.0 && f.is_sign_negative() {
43 Value::Number(Number::from(0u64))
44 } else {
45 Value::Number(n)
46 }
47 } else {
48 Value::Number(n)
49 }
50 }
51 Value::Object(obj) => {
52 let normalized: IndexMap<String, Value> =
53 obj.into_iter().map(|(k, v)| (k, normalize(v))).collect();
54 Value::Object(normalized)
55 }
56 Value::Array(arr) => {
57 let normalized: Vec<Value> = arr.into_iter().map(normalize).collect();
58 Value::Array(normalized)
59 }
60 _ => value,
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use core::f64;
67
68 use serde_json::json;
69
70 use super::*;
71
72 #[test]
73 fn test_normalize_nan() {
74 let value = Value::from(json!(f64::NAN));
75 let normalized = normalize(value);
76 assert_eq!(normalized, Value::from(json!(null)));
77 }
78
79 #[test]
80 fn test_normalize_infinity() {
81 let value = Value::from(json!(f64::INFINITY));
82 let normalized = normalize(value);
83 assert_eq!(normalized, Value::from(json!(null)));
84
85 let value = Value::from(json!(f64::NEG_INFINITY));
86 let normalized = normalize(value);
87 assert_eq!(normalized, Value::from(json!(null)));
88 }
89
90 #[test]
91 fn test_normalize_negative_zero() {
92 let value = Value::from(json!(-0.0));
93 let normalized = normalize(value);
94 assert_eq!(normalized, Value::from(json!(0)));
95 }
96
97 #[test]
98 fn test_normalize_nested() {
99 let value = Value::from(json!({
100 "a": f64::NAN,
101 "b": {
102 "c": f64::INFINITY
103 },
104 "d": [1, f64::NAN, 3]
105 }));
106
107 let normalized = normalize(value);
108 assert_eq!(
109 normalized,
110 Value::from(json!({
111 "a": null,
112 "b": {
113 "c": null
114 },
115 "d": [1, null, 3]
116 }))
117 );
118 }
119
120 #[test]
121 fn test_normalize_normal_values() {
122 let value = Value::from(json!({
123 "name": "Alice",
124 "age": 30,
125 "score": f64::consts::PI
126 }));
127
128 let normalized = normalize(value.clone());
129 assert_eq!(normalized, value);
130 }
131}