1use std::io::{Read, Write};
2
3use indexmap::IndexMap;
4use serde::Serialize;
5
6use crate::format::{FormatOptions, FormatReader, FormatWriter};
7use crate::value::Value;
8
9fn sort_value_keys(value: &Value) -> Value {
11 match value {
12 Value::Object(map) => {
13 let mut sorted: IndexMap<String, Value> = IndexMap::new();
14 let mut keys: Vec<&String> = map.keys().collect();
15 keys.sort();
16 for key in keys {
17 sorted.insert(key.clone(), sort_value_keys(&map[key]));
18 }
19 Value::Object(sorted)
20 }
21 Value::Array(arr) => Value::Array(arr.iter().map(sort_value_keys).collect()),
22 other => other.clone(),
23 }
24}
25
26pub fn from_json_value(v: serde_json::Value) -> Value {
28 match v {
29 serde_json::Value::Null => Value::Null,
30 serde_json::Value::Bool(b) => Value::Bool(b),
31 serde_json::Value::Number(n) => {
32 if let Some(i) = n.as_i64() {
33 Value::Integer(i)
34 } else if let Some(f) = n.as_f64() {
35 Value::Float(f)
36 } else {
37 Value::Float(n.as_f64().unwrap_or(f64::NAN))
39 }
40 }
41 serde_json::Value::String(s) => Value::String(s),
42 serde_json::Value::Array(arr) => {
43 Value::Array(arr.into_iter().map(from_json_value).collect())
44 }
45 serde_json::Value::Object(map) => {
46 let obj: IndexMap<String, Value> = map
47 .into_iter()
48 .map(|(k, v)| (k, from_json_value(v)))
49 .collect();
50 Value::Object(obj)
51 }
52 }
53}
54
55pub fn to_json_value(v: &Value) -> serde_json::Value {
57 match v {
58 Value::Null => serde_json::Value::Null,
59 Value::Bool(b) => serde_json::Value::Bool(*b),
60 Value::Integer(n) => serde_json::Value::Number((*n).into()),
61 Value::Float(f) => serde_json::Number::from_f64(*f)
62 .map(serde_json::Value::Number)
63 .unwrap_or(serde_json::Value::Null),
64 Value::String(s) => serde_json::Value::String(s.clone()),
65 Value::Array(arr) => serde_json::Value::Array(arr.iter().map(to_json_value).collect()),
66 Value::Object(map) => {
67 let obj: serde_json::Map<String, serde_json::Value> = map
68 .iter()
69 .map(|(k, v)| (k.clone(), to_json_value(v)))
70 .collect();
71 serde_json::Value::Object(obj)
72 }
73 }
74}
75
76pub struct JsonReader;
78
79impl FormatReader for JsonReader {
80 fn read(&self, input: &str) -> anyhow::Result<Value> {
81 let json_val: serde_json::Value = serde_json::from_str(input).map_err(|e| {
82 let line = e.line();
83 let column = e.column();
84 let line_text = input
85 .lines()
86 .nth(line.saturating_sub(1))
87 .unwrap_or("")
88 .to_string();
89 crate::error::DkitError::ParseErrorAt {
90 format: "JSON".to_string(),
91 source: Box::new(e),
92 line,
93 column,
94 line_text,
95 }
96 })?;
97 Ok(from_json_value(json_val))
98 }
99
100 fn read_from_reader(&self, mut reader: impl Read) -> anyhow::Result<Value> {
101 let json_val: serde_json::Value = serde_json::from_reader(&mut reader).map_err(|e| {
102 crate::error::DkitError::ParseError {
103 format: "JSON".to_string(),
104 source: Box::new(e),
105 }
106 })?;
107 Ok(from_json_value(json_val))
108 }
109}
110
111#[derive(Default)]
113pub struct JsonWriter {
114 options: FormatOptions,
115}
116
117impl JsonWriter {
118 pub fn new(options: FormatOptions) -> Self {
119 Self { options }
120 }
121}
122
123impl JsonWriter {
124 fn serialize_with_indent(json_val: &serde_json::Value, indent: &str) -> anyhow::Result<String> {
126 let mut buf = Vec::new();
127 let formatter = serde_json::ser::PrettyFormatter::with_indent(indent.as_bytes());
128 let mut ser = serde_json::Serializer::with_formatter(&mut buf, formatter);
129 serde_json::Value::serialize(json_val, &mut ser).map_err(|e| {
130 crate::error::DkitError::WriteError {
131 format: "JSON".to_string(),
132 source: Box::new(e),
133 }
134 })?;
135 Ok(String::from_utf8(buf)?)
136 }
137
138 fn serialize_with_indent_to_writer(
139 json_val: &serde_json::Value,
140 indent: &str,
141 writer: impl Write,
142 ) -> anyhow::Result<()> {
143 let formatter = serde_json::ser::PrettyFormatter::with_indent(indent.as_bytes());
144 let mut ser = serde_json::Serializer::with_formatter(writer, formatter);
145 serde_json::Value::serialize(json_val, &mut ser).map_err(|e| {
146 crate::error::DkitError::WriteError {
147 format: "JSON".to_string(),
148 source: Box::new(e),
149 }
150 })?;
151 Ok(())
152 }
153
154 fn resolve_indent(&self) -> Option<String> {
156 self.options.indent.as_ref().map(|v| {
157 if v.eq_ignore_ascii_case("tab") {
158 "\t".to_string()
159 } else if let Ok(n) = v.parse::<usize>() {
160 " ".repeat(n)
161 } else {
162 " ".to_string()
164 }
165 })
166 }
167
168 fn prepare_value(&self, value: &Value) -> serde_json::Value {
169 let value = if self.options.sort_keys {
170 sort_value_keys(value)
171 } else {
172 value.clone()
173 };
174 to_json_value(&value)
175 }
176}
177
178impl FormatWriter for JsonWriter {
179 fn write(&self, value: &Value) -> anyhow::Result<String> {
180 let json_val = self.prepare_value(value);
181 let output = if self.options.compact {
182 serde_json::to_string(&json_val).map_err(|e| crate::error::DkitError::WriteError {
183 format: "JSON".to_string(),
184 source: Box::new(e),
185 })?
186 } else if let Some(indent) = self.resolve_indent() {
187 Self::serialize_with_indent(&json_val, &indent)?
188 } else if self.options.pretty {
189 serde_json::to_string_pretty(&json_val).map_err(|e| {
190 crate::error::DkitError::WriteError {
191 format: "JSON".to_string(),
192 source: Box::new(e),
193 }
194 })?
195 } else {
196 serde_json::to_string(&json_val).map_err(|e| crate::error::DkitError::WriteError {
197 format: "JSON".to_string(),
198 source: Box::new(e),
199 })?
200 };
201 Ok(output)
202 }
203
204 fn write_to_writer(&self, value: &Value, mut writer: impl Write) -> anyhow::Result<()> {
205 let json_val = self.prepare_value(value);
206 if self.options.compact {
207 serde_json::to_writer(&mut writer, &json_val)
208 } else if let Some(indent) = self.resolve_indent() {
209 return Self::serialize_with_indent_to_writer(&json_val, &indent, &mut writer);
210 } else if self.options.pretty {
211 serde_json::to_writer_pretty(&mut writer, &json_val)
212 } else {
213 serde_json::to_writer(&mut writer, &json_val)
214 }
215 .map_err(|e| crate::error::DkitError::WriteError {
216 format: "JSON".to_string(),
217 source: Box::new(e),
218 })?;
219 Ok(())
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226
227 #[test]
230 fn test_convert_null() {
231 let v = from_json_value(serde_json::Value::Null);
232 assert_eq!(v, Value::Null);
233 }
234
235 #[test]
236 fn test_convert_bool() {
237 assert_eq!(
238 from_json_value(serde_json::Value::Bool(true)),
239 Value::Bool(true)
240 );
241 }
242
243 #[test]
244 fn test_convert_integer() {
245 let v = from_json_value(serde_json::json!(42));
246 assert_eq!(v, Value::Integer(42));
247 }
248
249 #[test]
250 fn test_convert_float() {
251 let v = from_json_value(serde_json::json!(3.14));
252 assert_eq!(v, Value::Float(3.14));
253 }
254
255 #[test]
256 fn test_convert_string() {
257 let v = from_json_value(serde_json::json!("hello"));
258 assert_eq!(v, Value::String("hello".to_string()));
259 }
260
261 #[test]
262 fn test_convert_array() {
263 let v = from_json_value(serde_json::json!([1, "two", null]));
264 let arr = v.as_array().unwrap();
265 assert_eq!(arr.len(), 3);
266 assert_eq!(arr[0], Value::Integer(1));
267 assert_eq!(arr[1], Value::String("two".to_string()));
268 assert_eq!(arr[2], Value::Null);
269 }
270
271 #[test]
272 fn test_convert_object() {
273 let v = from_json_value(serde_json::json!({"name": "dkit", "version": 1}));
274 let obj = v.as_object().unwrap();
275 assert_eq!(obj.get("name"), Some(&Value::String("dkit".to_string())));
276 assert_eq!(obj.get("version"), Some(&Value::Integer(1)));
277 }
278
279 #[test]
280 fn test_convert_nested() {
281 let v = from_json_value(serde_json::json!({
282 "users": [
283 {"name": "Alice", "age": 30},
284 {"name": "Bob", "age": 25}
285 ]
286 }));
287 let users = v
288 .as_object()
289 .unwrap()
290 .get("users")
291 .unwrap()
292 .as_array()
293 .unwrap();
294 assert_eq!(users.len(), 2);
295 assert_eq!(
296 users[0].as_object().unwrap().get("name"),
297 Some(&Value::String("Alice".to_string()))
298 );
299 }
300
301 #[test]
304 fn test_roundtrip_primitives() {
305 let values = vec![
306 Value::Null,
307 Value::Bool(false),
308 Value::Integer(100),
309 Value::Float(2.718),
310 Value::String("test".to_string()),
311 ];
312 for v in values {
313 let json = to_json_value(&v);
314 let back = from_json_value(json);
315 assert_eq!(back, v);
316 }
317 }
318
319 #[test]
320 fn test_roundtrip_complex() {
321 let mut map = IndexMap::new();
322 map.insert(
323 "key".to_string(),
324 Value::Array(vec![Value::Integer(1), Value::Null]),
325 );
326 let original = Value::Object(map);
327 let json = to_json_value(&original);
328 let back = from_json_value(json);
329 assert_eq!(back, original);
330 }
331
332 #[test]
335 fn test_reader_simple_object() {
336 let reader = JsonReader;
337 let v = reader.read(r#"{"name": "dkit", "count": 42}"#).unwrap();
338 let obj = v.as_object().unwrap();
339 assert_eq!(obj.get("name"), Some(&Value::String("dkit".to_string())));
340 assert_eq!(obj.get("count"), Some(&Value::Integer(42)));
341 }
342
343 #[test]
344 fn test_reader_array() {
345 let reader = JsonReader;
346 let v = reader.read("[1, 2, 3]").unwrap();
347 assert_eq!(v.as_array().unwrap().len(), 3);
348 }
349
350 #[test]
351 fn test_reader_invalid_json() {
352 let reader = JsonReader;
353 let result = reader.read("{invalid}");
354 assert!(result.is_err());
355 }
356
357 #[test]
358 fn test_reader_empty_object() {
359 let reader = JsonReader;
360 let v = reader.read("{}").unwrap();
361 assert!(v.as_object().unwrap().is_empty());
362 }
363
364 #[test]
365 fn test_reader_empty_array() {
366 let reader = JsonReader;
367 let v = reader.read("[]").unwrap();
368 assert!(v.as_array().unwrap().is_empty());
369 }
370
371 #[test]
372 fn test_reader_from_reader() {
373 let reader = JsonReader;
374 let input = r#"{"x": 1}"#.as_bytes();
375 let v = reader.read_from_reader(input).unwrap();
376 assert_eq!(v.as_object().unwrap().get("x"), Some(&Value::Integer(1)));
377 }
378
379 #[test]
380 fn test_reader_from_reader_invalid() {
381 let reader = JsonReader;
382 let input = b"not json" as &[u8];
383 assert!(reader.read_from_reader(input).is_err());
384 }
385
386 #[test]
389 fn test_writer_pretty() {
390 let writer = JsonWriter::default(); let v = Value::Object({
392 let mut m = IndexMap::new();
393 m.insert("a".to_string(), Value::Integer(1));
394 m
395 });
396 let output = writer.write(&v).unwrap();
397 assert!(output.contains('\n'));
398 assert!(output.contains(" ")); }
400
401 #[test]
402 fn test_writer_compact() {
403 let writer = JsonWriter::new(FormatOptions {
404 compact: true,
405 pretty: false,
406 ..Default::default()
407 });
408 let v = Value::Object({
409 let mut m = IndexMap::new();
410 m.insert("a".to_string(), Value::Integer(1));
411 m
412 });
413 let output = writer.write(&v).unwrap();
414 assert_eq!(output, r#"{"a":1}"#);
415 }
416
417 #[test]
418 fn test_writer_null() {
419 let writer = JsonWriter::new(FormatOptions {
420 compact: true,
421 ..Default::default()
422 });
423 assert_eq!(writer.write(&Value::Null).unwrap(), "null");
424 }
425
426 #[test]
427 fn test_writer_to_writer() {
428 let writer = JsonWriter::new(FormatOptions {
429 compact: true,
430 ..Default::default()
431 });
432 let mut buf = Vec::new();
433 writer
434 .write_to_writer(&Value::Integer(42), &mut buf)
435 .unwrap();
436 assert_eq!(String::from_utf8(buf).unwrap(), "42");
437 }
438
439 #[test]
440 fn test_writer_nan_becomes_null() {
441 let writer = JsonWriter::new(FormatOptions {
442 compact: true,
443 ..Default::default()
444 });
445 let output = writer.write(&Value::Float(f64::NAN)).unwrap();
446 assert_eq!(output, "null");
447 }
448
449 #[test]
452 fn test_large_array() {
453 let reader = JsonReader;
454 let arr: Vec<String> = (0..1000).map(|i| format!("{i}")).collect();
455 let json = serde_json::to_string(&arr).unwrap();
456 let v = reader.read(&json).unwrap();
457 assert_eq!(v.as_array().unwrap().len(), 1000);
458 }
459
460 #[test]
463 fn test_unicode_string() {
464 let reader = JsonReader;
465 let v = reader.read(r#"{"emoji": "🎉", "korean": "한글"}"#).unwrap();
466 let obj = v.as_object().unwrap();
467 assert_eq!(obj.get("emoji"), Some(&Value::String("🎉".to_string())));
468 assert_eq!(obj.get("korean"), Some(&Value::String("한글".to_string())));
469 }
470
471 #[test]
472 fn test_negative_numbers() {
473 let reader = JsonReader;
474 let v = reader
475 .read(r#"{"neg_int": -42, "neg_float": -3.14}"#)
476 .unwrap();
477 let obj = v.as_object().unwrap();
478 assert_eq!(obj.get("neg_int"), Some(&Value::Integer(-42)));
479 assert_eq!(obj.get("neg_float"), Some(&Value::Float(-3.14)));
480 }
481
482 #[test]
483 fn test_deeply_nested() {
484 let reader = JsonReader;
485 let v = reader.read(r#"{"a": {"b": {"c": {"d": 1}}}}"#).unwrap();
486 let d = v
487 .as_object()
488 .unwrap()
489 .get("a")
490 .unwrap()
491 .as_object()
492 .unwrap()
493 .get("b")
494 .unwrap()
495 .as_object()
496 .unwrap()
497 .get("c")
498 .unwrap()
499 .as_object()
500 .unwrap()
501 .get("d")
502 .unwrap();
503 assert_eq!(d, &Value::Integer(1));
504 }
505
506 #[test]
509 fn test_writer_indent_2_spaces() {
510 let writer = JsonWriter::new(FormatOptions {
511 indent: Some("2".to_string()),
512 ..Default::default()
513 });
514 let v = Value::Object({
515 let mut m = IndexMap::new();
516 m.insert("a".to_string(), Value::Integer(1));
517 m
518 });
519 let output = writer.write(&v).unwrap();
520 assert!(output.contains("\n \"a\""));
521 assert!(!output.contains(" \"a\"")); }
523
524 #[test]
525 fn test_writer_indent_4_spaces() {
526 let writer = JsonWriter::new(FormatOptions {
527 indent: Some("4".to_string()),
528 ..Default::default()
529 });
530 let v = Value::Object({
531 let mut m = IndexMap::new();
532 m.insert("x".to_string(), Value::Integer(42));
533 m
534 });
535 let output = writer.write(&v).unwrap();
536 assert!(output.contains("\n \"x\""));
537 }
538
539 #[test]
540 fn test_writer_indent_tab() {
541 let writer = JsonWriter::new(FormatOptions {
542 indent: Some("tab".to_string()),
543 ..Default::default()
544 });
545 let v = Value::Object({
546 let mut m = IndexMap::new();
547 m.insert("a".to_string(), Value::Integer(1));
548 m
549 });
550 let output = writer.write(&v).unwrap();
551 assert!(output.contains("\n\t\"a\""));
552 }
553
554 #[test]
555 fn test_writer_sort_keys() {
556 let writer = JsonWriter::new(FormatOptions {
557 compact: true,
558 sort_keys: true,
559 ..Default::default()
560 });
561 let v = Value::Object({
562 let mut m = IndexMap::new();
563 m.insert("zebra".to_string(), Value::Integer(1));
564 m.insert("apple".to_string(), Value::Integer(2));
565 m.insert("mango".to_string(), Value::Integer(3));
566 m
567 });
568 let output = writer.write(&v).unwrap();
569 assert_eq!(output, r#"{"apple":2,"mango":3,"zebra":1}"#);
570 }
571
572 #[test]
573 fn test_writer_sort_keys_nested() {
574 let writer = JsonWriter::new(FormatOptions {
575 compact: true,
576 sort_keys: true,
577 ..Default::default()
578 });
579 let v = Value::Object({
580 let mut m = IndexMap::new();
581 m.insert(
582 "z".to_string(),
583 Value::Object({
584 let mut inner = IndexMap::new();
585 inner.insert("b".to_string(), Value::Integer(2));
586 inner.insert("a".to_string(), Value::Integer(1));
587 inner
588 }),
589 );
590 m.insert("a".to_string(), Value::Integer(0));
591 m
592 });
593 let output = writer.write(&v).unwrap();
594 assert_eq!(output, r#"{"a":0,"z":{"a":1,"b":2}}"#);
595 }
596
597 #[test]
598 fn test_writer_indent_and_sort_keys() {
599 let writer = JsonWriter::new(FormatOptions {
600 indent: Some("2".to_string()),
601 sort_keys: true,
602 ..Default::default()
603 });
604 let v = Value::Object({
605 let mut m = IndexMap::new();
606 m.insert("c".to_string(), Value::Integer(3));
607 m.insert("a".to_string(), Value::Integer(1));
608 m.insert("b".to_string(), Value::Integer(2));
609 m
610 });
611 let output = writer.write(&v).unwrap();
612 assert!(output.contains("\"a\": 1"));
614 let keys_pos_a = output.find("\"a\"").unwrap();
615 let keys_pos_b = output.find("\"b\"").unwrap();
616 let keys_pos_c = output.find("\"c\"").unwrap();
617 assert!(keys_pos_a < keys_pos_b);
618 assert!(keys_pos_b < keys_pos_c);
619 }
620
621 #[test]
622 fn test_writer_compact_overrides_indent() {
623 let writer = JsonWriter::new(FormatOptions {
624 compact: true,
625 indent: Some("4".to_string()),
626 ..Default::default()
627 });
628 let v = Value::Object({
629 let mut m = IndexMap::new();
630 m.insert("a".to_string(), Value::Integer(1));
631 m
632 });
633 let output = writer.write(&v).unwrap();
634 assert_eq!(output, r#"{"a":1}"#);
635 }
636
637 #[test]
638 fn test_writer_to_writer_with_indent() {
639 let writer = JsonWriter::new(FormatOptions {
640 indent: Some("2".to_string()),
641 ..Default::default()
642 });
643 let v = Value::Object({
644 let mut m = IndexMap::new();
645 m.insert("key".to_string(), Value::String("val".to_string()));
646 m
647 });
648 let mut buf = Vec::new();
649 writer.write_to_writer(&v, &mut buf).unwrap();
650 let output = String::from_utf8(buf).unwrap();
651 assert!(output.contains("\n \"key\""));
652 }
653
654 #[test]
655 fn test_writer_to_writer_with_sort_keys() {
656 let writer = JsonWriter::new(FormatOptions {
657 compact: true,
658 sort_keys: true,
659 ..Default::default()
660 });
661 let v = Value::Object({
662 let mut m = IndexMap::new();
663 m.insert("z".to_string(), Value::Integer(1));
664 m.insert("a".to_string(), Value::Integer(2));
665 m
666 });
667 let mut buf = Vec::new();
668 writer.write_to_writer(&v, &mut buf).unwrap();
669 let output = String::from_utf8(buf).unwrap();
670 assert_eq!(output, r#"{"a":2,"z":1}"#);
671 }
672}