pepl_stdlib/modules/
json.rs1use std::collections::BTreeMap;
7
8use crate::error::StdlibError;
9use crate::module::StdlibModule;
10use crate::value::{ResultValue, Value};
11
12const MAX_DEPTH: usize = 32;
14
15pub struct JsonModule;
17
18impl JsonModule {
19 pub fn new() -> Self {
20 Self
21 }
22}
23
24impl Default for JsonModule {
25 fn default() -> Self {
26 Self::new()
27 }
28}
29
30impl StdlibModule for JsonModule {
31 fn name(&self) -> &'static str {
32 "json"
33 }
34
35 fn has_function(&self, function: &str) -> bool {
36 matches!(function, "parse" | "stringify")
37 }
38
39 fn call(&self, function: &str, args: Vec<Value>) -> Result<Value, StdlibError> {
40 match function {
41 "parse" => self.parse(args),
42 "stringify" => self.stringify(args),
43 _ => Err(StdlibError::unknown_function("json", function)),
44 }
45 }
46}
47
48impl JsonModule {
49 fn parse(&self, args: Vec<Value>) -> Result<Value, StdlibError> {
52 if args.len() != 1 {
53 return Err(StdlibError::wrong_args("json.parse", 1, args.len()));
54 }
55 let s = extract_string("json.parse", &args[0], 1)?;
56
57 match serde_json::from_str::<serde_json::Value>(s) {
58 Ok(json_val) => match json_to_value(&json_val, 0) {
59 Ok(v) => Ok(v.ok()),
60 Err(msg) => Ok(Value::String(msg).err()),
61 },
62 Err(e) => Ok(Value::String(format!("JSON parse error: {}", e)).err()),
63 }
64 }
65
66 fn stringify(&self, args: Vec<Value>) -> Result<Value, StdlibError> {
69 if args.len() != 1 {
70 return Err(StdlibError::wrong_args("json.stringify", 1, args.len()));
71 }
72 let json_val = value_to_json(&args[0]);
73 Ok(Value::String(
74 serde_json::to_string(&json_val).unwrap_or_else(|_| "null".to_string()),
75 ))
76 }
77}
78
79fn json_to_value(json: &serde_json::Value, depth: usize) -> Result<Value, String> {
83 if depth > MAX_DEPTH {
84 return Err(format!(
85 "JSON nesting exceeds maximum depth of {}",
86 MAX_DEPTH
87 ));
88 }
89
90 match json {
91 serde_json::Value::Null => Ok(Value::Nil),
92 serde_json::Value::Bool(b) => Ok(Value::Bool(*b)),
93 serde_json::Value::Number(n) => Ok(Value::Number(n.as_f64().unwrap_or(0.0))),
94 serde_json::Value::String(s) => Ok(Value::String(s.clone())),
95 serde_json::Value::Array(arr) => {
96 let mut items = Vec::with_capacity(arr.len());
97 for item in arr {
98 items.push(json_to_value(item, depth + 1)?);
99 }
100 Ok(Value::List(items))
101 }
102 serde_json::Value::Object(obj) => {
103 let mut fields = BTreeMap::new();
104 for (key, val) in obj {
105 fields.insert(key.clone(), json_to_value(val, depth + 1)?);
106 }
107 Ok(Value::record(fields))
108 }
109 }
110}
111
112fn value_to_json(value: &Value) -> serde_json::Value {
114 match value {
115 Value::Nil => serde_json::Value::Null,
116 Value::Bool(b) => serde_json::Value::Bool(*b),
117 Value::Number(n) => {
118 if n.is_finite() {
119 serde_json::Value::Number(
120 serde_json::Number::from_f64(*n).unwrap_or_else(|| serde_json::Number::from(0)),
121 )
122 } else {
123 serde_json::Value::Null }
125 }
126 Value::String(s) => serde_json::Value::String(s.clone()),
127 Value::List(items) => serde_json::Value::Array(items.iter().map(value_to_json).collect()),
128 Value::Record { fields, .. } => {
129 let obj: serde_json::Map<String, serde_json::Value> = fields
130 .iter()
131 .map(|(k, v)| (k.clone(), value_to_json(v)))
132 .collect();
133 serde_json::Value::Object(obj)
134 }
135 Value::Color { r, g, b, a } => {
136 let mut obj = serde_json::Map::new();
137 obj.insert("r".into(), value_to_json(&Value::Number(*r)));
138 obj.insert("g".into(), value_to_json(&Value::Number(*g)));
139 obj.insert("b".into(), value_to_json(&Value::Number(*b)));
140 obj.insert("a".into(), value_to_json(&Value::Number(*a)));
141 serde_json::Value::Object(obj)
142 }
143 Value::Result(rv) => match rv.as_ref() {
144 ResultValue::Ok(v) => {
145 let mut obj = serde_json::Map::new();
146 obj.insert("ok".into(), value_to_json(v));
147 serde_json::Value::Object(obj)
148 }
149 ResultValue::Err(v) => {
150 let mut obj = serde_json::Map::new();
151 obj.insert("err".into(), value_to_json(v));
152 serde_json::Value::Object(obj)
153 }
154 },
155 Value::SumVariant {
156 type_name,
157 variant,
158 fields,
159 } => {
160 let mut obj = serde_json::Map::new();
161 obj.insert("_type".into(), serde_json::Value::String(type_name.clone()));
162 obj.insert(
163 "_variant".into(),
164 serde_json::Value::String(variant.clone()),
165 );
166 if !fields.is_empty() {
167 obj.insert(
168 "_fields".into(),
169 serde_json::Value::Array(fields.iter().map(value_to_json).collect()),
170 );
171 }
172 serde_json::Value::Object(obj)
173 }
174 Value::Function(_) => serde_json::Value::String("<function>".to_string()),
175 }
176}
177
178fn extract_string<'a>(func: &str, val: &'a Value, pos: usize) -> Result<&'a str, StdlibError> {
181 match val {
182 Value::String(s) => Ok(s),
183 _ => Err(StdlibError::type_mismatch(
184 func,
185 pos,
186 "string",
187 val.type_name(),
188 )),
189 }
190}