1use std::io::{Read, Write};
2
3use indexmap::IndexMap;
4
5use crate::format::{FormatOptions, FormatReader, FormatWriter};
6use crate::value::Value;
7
8pub fn from_json_value(v: serde_json::Value) -> Value {
10 match v {
11 serde_json::Value::Null => Value::Null,
12 serde_json::Value::Bool(b) => Value::Bool(b),
13 serde_json::Value::Number(n) => {
14 if let Some(i) = n.as_i64() {
15 Value::Integer(i)
16 } else if let Some(f) = n.as_f64() {
17 Value::Float(f)
18 } else {
19 Value::Float(n.as_f64().unwrap_or(f64::NAN))
21 }
22 }
23 serde_json::Value::String(s) => Value::String(s),
24 serde_json::Value::Array(arr) => {
25 Value::Array(arr.into_iter().map(from_json_value).collect())
26 }
27 serde_json::Value::Object(map) => {
28 let obj: IndexMap<String, Value> = map
29 .into_iter()
30 .map(|(k, v)| (k, from_json_value(v)))
31 .collect();
32 Value::Object(obj)
33 }
34 }
35}
36
37pub fn to_json_value(v: &Value) -> serde_json::Value {
39 match v {
40 Value::Null => serde_json::Value::Null,
41 Value::Bool(b) => serde_json::Value::Bool(*b),
42 Value::Integer(n) => serde_json::Value::Number((*n).into()),
43 Value::Float(f) => serde_json::Number::from_f64(*f)
44 .map(serde_json::Value::Number)
45 .unwrap_or(serde_json::Value::Null),
46 Value::String(s) => serde_json::Value::String(s.clone()),
47 Value::Array(arr) => serde_json::Value::Array(arr.iter().map(to_json_value).collect()),
48 Value::Object(map) => {
49 let obj: serde_json::Map<String, serde_json::Value> = map
50 .iter()
51 .map(|(k, v)| (k.clone(), to_json_value(v)))
52 .collect();
53 serde_json::Value::Object(obj)
54 }
55 }
56}
57
58pub struct JsonReader;
60
61impl FormatReader for JsonReader {
62 fn read(&self, input: &str) -> anyhow::Result<Value> {
63 let json_val: serde_json::Value = serde_json::from_str(input).map_err(|e| {
64 let line = e.line();
65 let column = e.column();
66 let line_text = input
67 .lines()
68 .nth(line.saturating_sub(1))
69 .unwrap_or("")
70 .to_string();
71 crate::error::DkitError::ParseErrorAt {
72 format: "JSON".to_string(),
73 source: Box::new(e),
74 line,
75 column,
76 line_text,
77 }
78 })?;
79 Ok(from_json_value(json_val))
80 }
81
82 fn read_from_reader(&self, mut reader: impl Read) -> anyhow::Result<Value> {
83 let json_val: serde_json::Value = serde_json::from_reader(&mut reader).map_err(|e| {
84 crate::error::DkitError::ParseError {
85 format: "JSON".to_string(),
86 source: Box::new(e),
87 }
88 })?;
89 Ok(from_json_value(json_val))
90 }
91}
92
93#[derive(Default)]
95pub struct JsonWriter {
96 options: FormatOptions,
97}
98
99impl JsonWriter {
100 pub fn new(options: FormatOptions) -> Self {
101 Self { options }
102 }
103}
104
105impl FormatWriter for JsonWriter {
106 fn write(&self, value: &Value) -> anyhow::Result<String> {
107 let json_val = to_json_value(value);
108 let output = if self.options.compact {
109 serde_json::to_string(&json_val)
110 } else if self.options.pretty {
111 serde_json::to_string_pretty(&json_val)
112 } else {
113 serde_json::to_string(&json_val)
114 };
115 output.map_err(|e| {
116 crate::error::DkitError::WriteError {
117 format: "JSON".to_string(),
118 source: Box::new(e),
119 }
120 .into()
121 })
122 }
123
124 fn write_to_writer(&self, value: &Value, mut writer: impl Write) -> anyhow::Result<()> {
125 let json_val = to_json_value(value);
126 let result = if self.options.compact {
127 serde_json::to_writer(&mut writer, &json_val)
128 } else if self.options.pretty {
129 serde_json::to_writer_pretty(&mut writer, &json_val)
130 } else {
131 serde_json::to_writer(&mut writer, &json_val)
132 };
133 result.map_err(|e| crate::error::DkitError::WriteError {
134 format: "JSON".to_string(),
135 source: Box::new(e),
136 })?;
137 Ok(())
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
148 fn test_convert_null() {
149 let v = from_json_value(serde_json::Value::Null);
150 assert_eq!(v, Value::Null);
151 }
152
153 #[test]
154 fn test_convert_bool() {
155 assert_eq!(
156 from_json_value(serde_json::Value::Bool(true)),
157 Value::Bool(true)
158 );
159 }
160
161 #[test]
162 fn test_convert_integer() {
163 let v = from_json_value(serde_json::json!(42));
164 assert_eq!(v, Value::Integer(42));
165 }
166
167 #[test]
168 fn test_convert_float() {
169 let v = from_json_value(serde_json::json!(3.14));
170 assert_eq!(v, Value::Float(3.14));
171 }
172
173 #[test]
174 fn test_convert_string() {
175 let v = from_json_value(serde_json::json!("hello"));
176 assert_eq!(v, Value::String("hello".to_string()));
177 }
178
179 #[test]
180 fn test_convert_array() {
181 let v = from_json_value(serde_json::json!([1, "two", null]));
182 let arr = v.as_array().unwrap();
183 assert_eq!(arr.len(), 3);
184 assert_eq!(arr[0], Value::Integer(1));
185 assert_eq!(arr[1], Value::String("two".to_string()));
186 assert_eq!(arr[2], Value::Null);
187 }
188
189 #[test]
190 fn test_convert_object() {
191 let v = from_json_value(serde_json::json!({"name": "dkit", "version": 1}));
192 let obj = v.as_object().unwrap();
193 assert_eq!(obj.get("name"), Some(&Value::String("dkit".to_string())));
194 assert_eq!(obj.get("version"), Some(&Value::Integer(1)));
195 }
196
197 #[test]
198 fn test_convert_nested() {
199 let v = from_json_value(serde_json::json!({
200 "users": [
201 {"name": "Alice", "age": 30},
202 {"name": "Bob", "age": 25}
203 ]
204 }));
205 let users = v
206 .as_object()
207 .unwrap()
208 .get("users")
209 .unwrap()
210 .as_array()
211 .unwrap();
212 assert_eq!(users.len(), 2);
213 assert_eq!(
214 users[0].as_object().unwrap().get("name"),
215 Some(&Value::String("Alice".to_string()))
216 );
217 }
218
219 #[test]
222 fn test_roundtrip_primitives() {
223 let values = vec![
224 Value::Null,
225 Value::Bool(false),
226 Value::Integer(100),
227 Value::Float(2.718),
228 Value::String("test".to_string()),
229 ];
230 for v in values {
231 let json = to_json_value(&v);
232 let back = from_json_value(json);
233 assert_eq!(back, v);
234 }
235 }
236
237 #[test]
238 fn test_roundtrip_complex() {
239 let mut map = IndexMap::new();
240 map.insert(
241 "key".to_string(),
242 Value::Array(vec![Value::Integer(1), Value::Null]),
243 );
244 let original = Value::Object(map);
245 let json = to_json_value(&original);
246 let back = from_json_value(json);
247 assert_eq!(back, original);
248 }
249
250 #[test]
253 fn test_reader_simple_object() {
254 let reader = JsonReader;
255 let v = reader.read(r#"{"name": "dkit", "count": 42}"#).unwrap();
256 let obj = v.as_object().unwrap();
257 assert_eq!(obj.get("name"), Some(&Value::String("dkit".to_string())));
258 assert_eq!(obj.get("count"), Some(&Value::Integer(42)));
259 }
260
261 #[test]
262 fn test_reader_array() {
263 let reader = JsonReader;
264 let v = reader.read("[1, 2, 3]").unwrap();
265 assert_eq!(v.as_array().unwrap().len(), 3);
266 }
267
268 #[test]
269 fn test_reader_invalid_json() {
270 let reader = JsonReader;
271 let result = reader.read("{invalid}");
272 assert!(result.is_err());
273 }
274
275 #[test]
276 fn test_reader_empty_object() {
277 let reader = JsonReader;
278 let v = reader.read("{}").unwrap();
279 assert!(v.as_object().unwrap().is_empty());
280 }
281
282 #[test]
283 fn test_reader_empty_array() {
284 let reader = JsonReader;
285 let v = reader.read("[]").unwrap();
286 assert!(v.as_array().unwrap().is_empty());
287 }
288
289 #[test]
290 fn test_reader_from_reader() {
291 let reader = JsonReader;
292 let input = r#"{"x": 1}"#.as_bytes();
293 let v = reader.read_from_reader(input).unwrap();
294 assert_eq!(v.as_object().unwrap().get("x"), Some(&Value::Integer(1)));
295 }
296
297 #[test]
298 fn test_reader_from_reader_invalid() {
299 let reader = JsonReader;
300 let input = b"not json" as &[u8];
301 assert!(reader.read_from_reader(input).is_err());
302 }
303
304 #[test]
307 fn test_writer_pretty() {
308 let writer = JsonWriter::default(); let v = Value::Object({
310 let mut m = IndexMap::new();
311 m.insert("a".to_string(), Value::Integer(1));
312 m
313 });
314 let output = writer.write(&v).unwrap();
315 assert!(output.contains('\n'));
316 assert!(output.contains(" ")); }
318
319 #[test]
320 fn test_writer_compact() {
321 let writer = JsonWriter::new(FormatOptions {
322 compact: true,
323 pretty: false,
324 ..Default::default()
325 });
326 let v = Value::Object({
327 let mut m = IndexMap::new();
328 m.insert("a".to_string(), Value::Integer(1));
329 m
330 });
331 let output = writer.write(&v).unwrap();
332 assert_eq!(output, r#"{"a":1}"#);
333 }
334
335 #[test]
336 fn test_writer_null() {
337 let writer = JsonWriter::new(FormatOptions {
338 compact: true,
339 ..Default::default()
340 });
341 assert_eq!(writer.write(&Value::Null).unwrap(), "null");
342 }
343
344 #[test]
345 fn test_writer_to_writer() {
346 let writer = JsonWriter::new(FormatOptions {
347 compact: true,
348 ..Default::default()
349 });
350 let mut buf = Vec::new();
351 writer
352 .write_to_writer(&Value::Integer(42), &mut buf)
353 .unwrap();
354 assert_eq!(String::from_utf8(buf).unwrap(), "42");
355 }
356
357 #[test]
358 fn test_writer_nan_becomes_null() {
359 let writer = JsonWriter::new(FormatOptions {
360 compact: true,
361 ..Default::default()
362 });
363 let output = writer.write(&Value::Float(f64::NAN)).unwrap();
364 assert_eq!(output, "null");
365 }
366
367 #[test]
370 fn test_large_array() {
371 let reader = JsonReader;
372 let arr: Vec<String> = (0..1000).map(|i| format!("{i}")).collect();
373 let json = serde_json::to_string(&arr).unwrap();
374 let v = reader.read(&json).unwrap();
375 assert_eq!(v.as_array().unwrap().len(), 1000);
376 }
377
378 #[test]
381 fn test_unicode_string() {
382 let reader = JsonReader;
383 let v = reader.read(r#"{"emoji": "🎉", "korean": "한글"}"#).unwrap();
384 let obj = v.as_object().unwrap();
385 assert_eq!(obj.get("emoji"), Some(&Value::String("🎉".to_string())));
386 assert_eq!(obj.get("korean"), Some(&Value::String("한글".to_string())));
387 }
388
389 #[test]
390 fn test_negative_numbers() {
391 let reader = JsonReader;
392 let v = reader
393 .read(r#"{"neg_int": -42, "neg_float": -3.14}"#)
394 .unwrap();
395 let obj = v.as_object().unwrap();
396 assert_eq!(obj.get("neg_int"), Some(&Value::Integer(-42)));
397 assert_eq!(obj.get("neg_float"), Some(&Value::Float(-3.14)));
398 }
399
400 #[test]
401 fn test_deeply_nested() {
402 let reader = JsonReader;
403 let v = reader.read(r#"{"a": {"b": {"c": {"d": 1}}}}"#).unwrap();
404 let d = v
405 .as_object()
406 .unwrap()
407 .get("a")
408 .unwrap()
409 .as_object()
410 .unwrap()
411 .get("b")
412 .unwrap()
413 .as_object()
414 .unwrap()
415 .get("c")
416 .unwrap()
417 .as_object()
418 .unwrap()
419 .get("d")
420 .unwrap();
421 assert_eq!(d, &Value::Integer(1));
422 }
423}