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