sage_runtime/stdlib/
json.rs1use serde_json::Value;
4
5pub fn json_parse(s: &str) -> Result<String, String> {
8 let _: Value = serde_json::from_str(s).map_err(|e| format!("invalid JSON: {}", e))?;
9 Ok(s.to_string())
10}
11
12#[must_use]
15pub fn json_get(json: &str, field: &str) -> Option<String> {
16 let value: Value = serde_json::from_str(json).ok()?;
17 match value.get(field)? {
18 Value::String(s) => Some(s.clone()),
19 other => Some(other.to_string()),
20 }
21}
22
23#[must_use]
26pub fn json_get_int(json: &str, field: &str) -> Option<i64> {
27 let value: Value = serde_json::from_str(json).ok()?;
28 value.get(field)?.as_i64()
29}
30
31#[must_use]
34pub fn json_get_float(json: &str, field: &str) -> Option<f64> {
35 let value: Value = serde_json::from_str(json).ok()?;
36 value.get(field)?.as_f64()
37}
38
39#[must_use]
42pub fn json_get_bool(json: &str, field: &str) -> Option<bool> {
43 let value: Value = serde_json::from_str(json).ok()?;
44 value.get(field)?.as_bool()
45}
46
47#[must_use]
51pub fn json_get_list(json: &str, field: &str) -> Option<Vec<String>> {
52 let value: Value = serde_json::from_str(json).ok()?;
53 let arr = value.get(field)?.as_array()?;
54 Some(
55 arr.iter()
56 .map(|v| match v {
57 Value::String(s) => s.clone(),
58 other => other.to_string(),
59 })
60 .collect(),
61 )
62}
63
64#[must_use]
67pub fn json_stringify_string(s: &str) -> String {
68 serde_json::to_string(s).unwrap_or_else(|_| format!("\"{}\"", s))
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn test_json_parse() {
77 assert!(json_parse(r#"{"name": "Alice"}"#).is_ok());
78 assert!(json_parse(r#"[1, 2, 3]"#).is_ok());
79 assert!(json_parse(r#"invalid json"#).is_err());
80 }
81
82 #[test]
83 fn test_json_get() {
84 let json = r#"{"name": "Alice", "age": 30}"#;
85 assert_eq!(json_get(json, "name"), Some("Alice".to_string()));
86 assert_eq!(json_get(json, "age"), Some("30".to_string()));
87 assert_eq!(json_get(json, "missing"), None);
88 }
89
90 #[test]
91 fn test_json_get_int() {
92 let json = r#"{"count": 42, "name": "test"}"#;
93 assert_eq!(json_get_int(json, "count"), Some(42));
94 assert_eq!(json_get_int(json, "name"), None);
95 assert_eq!(json_get_int(json, "missing"), None);
96 }
97
98 #[test]
99 fn test_json_get_float() {
100 let json = r#"{"value": 3.14, "count": 42}"#;
101 assert!((json_get_float(json, "value").unwrap() - 3.14).abs() < 0.001);
102 assert_eq!(json_get_float(json, "count"), Some(42.0));
103 }
104
105 #[test]
106 fn test_json_get_bool() {
107 let json = r#"{"active": true, "deleted": false}"#;
108 assert_eq!(json_get_bool(json, "active"), Some(true));
109 assert_eq!(json_get_bool(json, "deleted"), Some(false));
110 assert_eq!(json_get_bool(json, "missing"), None);
111 }
112
113 #[test]
114 fn test_json_get_list() {
115 let json = r#"{"items": ["a", "b", "c"], "numbers": [1, 2, 3]}"#;
116 assert_eq!(
117 json_get_list(json, "items"),
118 Some(vec!["a".to_string(), "b".to_string(), "c".to_string()])
119 );
120 assert_eq!(
121 json_get_list(json, "numbers"),
122 Some(vec!["1".to_string(), "2".to_string(), "3".to_string()])
123 );
124 assert_eq!(json_get_list(json, "missing"), None);
125 }
126
127 #[test]
128 fn test_json_stringify_string() {
129 assert_eq!(json_stringify_string("hello"), r#""hello""#);
130 assert_eq!(json_stringify_string("hello\nworld"), r#""hello\nworld""#);
131 }
132}