Skip to main content

windjammer_runtime/
json.rs

1//! JSON serialization and deserialization
2//!
3//! Windjammer's `std::json` module maps to these functions.
4
5use serde_json::Value;
6
7/// Parse JSON string into a Value
8pub fn parse(s: &str) -> Result<Value, String> {
9    serde_json::from_str(s).map_err(|e| e.to_string())
10}
11
12/// Convert Value to JSON string
13pub fn stringify(value: &Value) -> Result<String, String> {
14    serde_json::to_string(value).map_err(|e| e.to_string())
15}
16
17/// Convert Value to pretty-printed JSON string
18pub fn stringify_pretty(value: &Value) -> Result<String, String> {
19    serde_json::to_string_pretty(value).map_err(|e| e.to_string())
20}
21
22/// Create a JSON object (map)
23pub fn object() -> Value {
24    Value::Object(serde_json::Map::new())
25}
26
27/// Create a JSON array
28pub fn array() -> Value {
29    Value::Array(Vec::new())
30}
31
32/// Create a JSON null value
33pub fn null() -> Value {
34    Value::Null
35}
36
37/// Create a JSON boolean value
38pub fn boolean(b: bool) -> Value {
39    Value::Bool(b)
40}
41
42/// Create a JSON number value from i64
43pub fn number_i64(n: i64) -> Value {
44    Value::Number(n.into())
45}
46
47/// Create a JSON number value from f64
48pub fn number_f64(n: f64) -> Result<Value, String> {
49    serde_json::Number::from_f64(n)
50        .map(Value::Number)
51        .ok_or_else(|| "Invalid number".to_string())
52}
53
54/// Create a JSON string value
55pub fn string(s: &str) -> Value {
56    Value::String(s.to_string())
57}
58
59/// Get value from object by key
60pub fn get<'a>(value: &'a Value, key: &str) -> Option<&'a Value> {
61    value.get(key)
62}
63
64/// Get string from object by key
65pub fn get_string(value: &Value, key: &str) -> Option<String> {
66    value
67        .get(key)
68        .and_then(|v| v.as_str().map(|s| s.to_string()))
69}
70
71/// Get number from object by key  
72pub fn get_number(value: &Value, key: &str) -> Option<f64> {
73    value.get(key).and_then(|v| v.as_f64())
74}
75
76/// Get boolean from object by key
77pub fn get_bool(value: &Value, key: &str) -> Option<bool> {
78    value.get(key).and_then(|v| v.as_bool())
79}
80
81/// Set value in object by key
82pub fn set(value: &mut Value, key: &str, new_value: Value) -> Result<(), String> {
83    if let Some(obj) = value.as_object_mut() {
84        obj.insert(key.to_string(), new_value);
85        Ok(())
86    } else {
87        Err("Value is not an object".to_string())
88    }
89}
90
91/// Get length of array or object
92pub fn len(value: &Value) -> usize {
93    match value {
94        Value::Array(arr) => arr.len(),
95        Value::Object(obj) => obj.len(),
96        _ => 0,
97    }
98}
99
100/// Check if array or object is empty
101pub fn is_empty(value: &Value) -> bool {
102    len(value) == 0
103}
104
105/// Get array element by index
106pub fn get_index(value: &Value, index: usize) -> Option<&Value> {
107    value.get(index)
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    #[test]
115    fn test_parse_stringify() {
116        let json_str = r#"{"name":"Alice","age":30}"#;
117        let value = parse(json_str).unwrap();
118        let result = stringify(&value).unwrap();
119
120        // Parse both to compare (order might differ)
121        let original: serde_json::Value = serde_json::from_str(json_str).unwrap();
122        let parsed: serde_json::Value = serde_json::from_str(&result).unwrap();
123        assert_eq!(original, parsed);
124    }
125
126    #[test]
127    fn test_constructors() {
128        assert_eq!(null(), Value::Null);
129        assert_eq!(boolean(true), Value::Bool(true));
130        assert_eq!(string("test"), Value::String("test".to_string()));
131        assert!(matches!(number_i64(42), Value::Number(_)));
132    }
133
134    #[test]
135    fn test_pretty_print() {
136        let value = parse(r#"{"a":1,"b":2}"#).unwrap();
137        let pretty = stringify_pretty(&value).unwrap();
138        assert!(pretty.contains('\n'));
139        assert!(pretty.contains("  "));
140    }
141
142    #[test]
143    fn test_get() {
144        let json = r#"{"name": "Alice", "age": 30, "active": true}"#;
145        let value = parse(json).unwrap();
146
147        assert!(get(&value, "name").is_some());
148        assert_eq!(get_string(&value, "name"), Some("Alice".to_string()));
149        assert_eq!(get_number(&value, "age"), Some(30.0));
150        assert_eq!(get_bool(&value, "active"), Some(true));
151    }
152
153    #[test]
154    fn test_set() {
155        let json = r#"{"name": "Alice"}"#;
156        let mut value = parse(json).unwrap();
157
158        let new_name = string("Bob");
159        let result = set(&mut value, "name", new_name);
160        assert!(result.is_ok());
161        assert_eq!(get_string(&value, "name"), Some("Bob".to_string()));
162    }
163
164    #[test]
165    fn test_len_is_empty() {
166        let json_array = r#"[1, 2, 3, 4, 5]"#;
167        let value_array = parse(json_array).unwrap();
168        assert_eq!(len(&value_array), 5);
169        assert!(!is_empty(&value_array));
170
171        let json_object = r#"{"a": 1, "b": 2}"#;
172        let value_object = parse(json_object).unwrap();
173        assert_eq!(len(&value_object), 2);
174        assert!(!is_empty(&value_object));
175
176        let empty_array = array();
177        assert_eq!(len(&empty_array), 0);
178        assert!(is_empty(&empty_array));
179    }
180}