1use core::fmt;
2use std::iter::Peekable;
3
4use owo_colors::{
5 colors::{Blue, BrightWhite, Green, White},
6 OwoColorize, Style,
7};
8
9pub fn parse_json(input: &str) -> Result<Json<'_>, ParseError> {
10 let mut json = Json::default();
11 json.parse_replace(input)?;
12 Ok(json)
13}
14
15#[derive(Clone, Default)]
16pub enum Json<'a> {
17 Object(JsonObject<'a>),
20 Array(Vec<Json<'a>>),
21 String(&'a str),
22 Value(&'a str),
23 #[default]
24 Null,
25 NullPrevObject(JsonObject<'a>),
26 NullPrevArray(Vec<Json<'a>>),
27}
28
29impl<'a> Json<'a> {
30 pub fn parse_replace(&mut self, input: &'a str) -> Result<(), ParseError> {
31 let mut chars = input.trim().char_indices().peekable();
32 if let Some((_, c)) = chars.peek() {
33 if *c != '{' && *c != '[' {
34 return Err(ParseError {
35 message: "JSON must be an object or array",
36 value: input.to_owned(),
37 index: 0,
38 });
39 }
40 }
41
42 self.parse_value_in_place(&mut chars, input)?;
43 Ok(())
44 }
45
46 pub fn get(&self, key: &str) -> &Json {
47 match self {
48 Json::Object(obj) => obj.get(key),
49 _ => &Json::Null,
50 }
51 }
52
53 pub fn get_mut(&'a mut self, key: &str) -> Option<&'a mut Json<'a>> {
54 match self {
55 Json::Object(obj) => obj.get_mut(key),
56 _ => None,
57 }
58 }
59
60 pub fn get_i(&self, index: usize) -> &Json {
61 match self {
62 Json::Array(arr) => arr.get(index).unwrap_or(&Json::Null),
63 _ => &Json::Null,
64 }
65 }
66
67 pub fn get_i_mut(&'a mut self, index: usize) -> Option<&'a mut Json<'a>> {
68 match self {
69 Json::Array(arr) => arr.get_mut(index),
70 _ => None,
71 }
72 }
73
74 pub fn remove(&mut self, key: &str) -> Option<Json<'a>> {
75 match self {
76 Json::Object(obj) => obj.remove(key),
77 _ => None,
78 }
79 }
80
81 pub fn remove_i(&mut self, index: usize) -> Option<Json<'a>> {
82 match self {
83 Json::Array(arr) => arr.get_mut(index).map(|e| e.replace(Json::Null)),
84 _ => None,
85 }
86 }
87
88 pub fn pointer(&self, pointer: &str) -> Option<&Json> {
100 if pointer.is_empty() {
101 return Some(self);
102 }
103 if !pointer.starts_with('/') {
104 return None;
105 }
106 pointer
107 .split('/')
108 .skip(1)
109 .map(|x| x.replace("~1", "/").replace("~0", "~"))
110 .try_fold(self, |target, token| match target {
111 Json::Object(map) => map.try_get(&token),
112 Json::Array(list) => parse_index(&token).and_then(|x| list.get(x)),
113 _ => None,
114 })
115 }
116
117 pub fn pointer_mut(&'a mut self, pointer: &str) -> Option<&'a mut Json<'a>> {
130 if pointer.is_empty() {
131 return Some(self);
132 }
133 if !pointer.starts_with('/') {
134 return None;
135 }
136
137 pointer
138 .split('/')
139 .skip(1)
140 .map(|x| x.replace("~1", "/").replace("~0", "~"))
141 .try_fold(self, |target, token| match target {
142 Json::Object(map) => map.get_mut(&token),
143 Json::Array(list) => parse_index(&token).and_then(move |x| list.get_mut(x)),
144 _ => None,
145 })
146 }
147
148 pub fn is_null(&self) -> bool {
149 matches!(
150 self,
151 Json::Null | Json::NullPrevObject(_) | Json::NullPrevArray(_)
152 )
153 }
154
155 pub fn is_empty(&self) -> bool {
156 match self {
157 Json::Object(obj) => obj.is_empty(),
158 Json::Array(arr) => arr.is_empty() || arr.iter().all(Json::is_null),
159 Json::String(s) => s.is_empty(),
160 Json::Value(_) => false,
161 Json::Null | Json::NullPrevObject(_) | Json::NullPrevArray(_) => true,
162 }
163 }
164
165 pub fn is_object(&self) -> bool { matches!(self, Json::Object(_)) }
166
167 pub fn is_array(&self) -> bool { matches!(self, Json::Array(_)) }
168
169 pub fn is_str(&self) -> bool { matches!(self, Json::String(_)) }
170
171 pub fn is_value(&self) -> bool { matches!(self, Json::Value(_)) }
172
173 pub fn as_object(&self) -> Option<&JsonObject<'a>> {
174 match self {
175 Json::Object(obj) => Some(obj),
176 _ => None,
177 }
178 }
179
180 pub fn as_object_mut(&mut self) -> Option<&mut JsonObject<'a>> {
181 match self {
182 Json::Object(obj) => Some(obj),
183 _ => None,
184 }
185 }
186
187 pub fn as_array(&self) -> Option<&Vec<Json<'a>>> {
188 match self {
189 Json::Array(arr) => Some(arr),
190 _ => None,
191 }
192 }
193
194 pub fn as_array_mut(&mut self) -> Option<&mut Vec<Json<'a>>> {
195 match self {
196 Json::Array(arr) => Some(arr),
197 _ => None,
198 }
199 }
200
201 pub fn as_str(&self) -> Option<&str> {
202 match self {
203 Json::String(s) => Some(s),
204 _ => None,
205 }
206 }
207
208 pub fn as_value(&self) -> Option<&str> {
209 match self {
210 Json::Value(v) => Some(v),
211 _ => None,
212 }
213 }
214
215 pub fn replace(&mut self, value: Json<'a>) -> Json<'a> { std::mem::replace(self, value) }
217
218 fn parse_value_in_place<I>(
219 &mut self,
220 chars: &mut Peekable<I>,
221 input: &'a str,
222 ) -> Result<(), ParseError>
223 where
224 I: Iterator<Item = (usize, char)>,
225 {
226 match chars.peek().map(|&(_, c)| c) {
227 Some('{') => {
228 if let Json::Object(obj) = self {
229 obj.parse_object_in_place(chars, input)?;
230 } else {
231 let this = self.replace(Json::Null);
232 if let Json::NullPrevObject(mut obj) = this {
233 obj.parse_object_in_place(chars, input)?;
234 *self = Json::Object(obj);
235 } else {
236 let mut obj = JsonObject(Vec::new());
237 obj.parse_object_in_place(chars, input)?;
238 *self = Json::Object(obj);
239 }
240 }
241 }
242 Some('[') => {
243 if let Json::Array(arr) = self {
244 parse_array_in_place(arr, chars, input)?;
245 } else {
246 let this = self.replace(Json::Null);
247 if let Json::NullPrevArray(mut arr) = this {
248 parse_array_in_place(&mut arr, chars, input)?;
249 *self = Json::Array(arr);
250 } else {
251 let mut arr = Vec::new();
252 parse_array_in_place(&mut arr, chars, input)?;
253 *self = Json::Array(arr);
254 }
255 }
256 }
257 Some('"') => {
258 *self = parse_string(chars, input)?;
259 }
260 Some('n') => {
261 parse_null(chars, input)?;
262 self.replace_with_null();
263 }
264 Some(']') => {
265 return Err(ParseError {
266 message: "Unexpected closing bracket",
267 value: input.to_owned(),
268 index: chars
269 .peek()
270 .map(|&(i, _)| i)
271 .unwrap_or_else(|| input.len() - 1),
272 })
273 }
274 Some('}') => {
275 return Err(ParseError {
276 message: "Unexpected closing brace",
277 value: input.to_owned(),
278 index: chars
279 .peek()
280 .map(|&(i, _)| i)
281 .unwrap_or_else(|| input.len() - 1),
282 })
283 }
284 Some(_) => {
285 *self = parse_raw_value(chars, input)?;
286 }
287 None => {
288 return Err(ParseError {
289 message: "Unexpected end of input",
290 value: input.to_owned(),
291 index: input.len(),
292 })
293 }
294 }
295
296 Ok(())
297 }
298
299 fn replace_with_null(&mut self) {
300 let prev = self.replace(Json::Null);
301
302 if let Json::Object(obj) = prev {
303 *self = Json::NullPrevObject(obj);
304 } else if let Json::Array(arr) = prev {
305 *self = Json::NullPrevArray(arr);
306 } else if matches!(prev, Json::NullPrevObject(_)) || matches!(prev, Json::NullPrevArray(_))
307 {
308 *self = prev;
309 }
310 }
311}
312
313#[derive(Clone, Default)]
314pub struct JsonObject<'a>(pub Vec<(&'a str, Json<'a>)>);
315
316impl<'a> JsonObject<'a> {
317 pub fn get(&self, key: &str) -> &Json { self.try_get(key).unwrap_or(&Json::Null) }
318
319 pub fn get_mut(&'a mut self, key: &str) -> Option<&'a mut Json<'a>> {
320 self.0.iter_mut().find(|(k, _)| k == &key).map(|(_, v)| v)
321 }
322
323 pub fn try_get(&self, key: &str) -> Option<&Json> {
324 self.0.iter().find(|(k, _)| k == &key).map(|(_, v)| v)
325 }
326
327 pub fn insert(&mut self, key: &'a str, value: Json<'a>) {
328 if let Some((_, v)) = self.0.iter_mut().find(|(k, _)| k == &key) {
329 *v = value;
330 } else {
331 self.0.push((key, value));
332 }
333 }
334
335 pub fn remove(&mut self, key: &str) -> Option<Json<'a>> {
336 if let Some((_, val)) = self.0.iter_mut().find(|(k, _)| k == &key) {
337 Some(val.replace(Json::Null))
338 } else {
339 None
340 }
341 }
342
343 pub fn is_empty(&self) -> bool {
344 if self.0.is_empty() {
345 return true;
346 }
347
348 self.0.iter().all(|(_, v)| v.is_null())
349 }
350
351 pub fn iter(&self) -> std::slice::Iter<(&'a str, Json<'a>)> { self.0.iter() }
352
353 pub fn iter_mut(&mut self) -> std::slice::IterMut<(&'a str, Json<'a>)> { self.0.iter_mut() }
354
355 pub fn parse_insert(&mut self, key: &'a str, input: &'a str) -> Result<(), ParseError> {
356 if let Some((old_key, value)) = self.0.iter_mut().find(|(k, _)| k == &key) {
357 *old_key = key;
358 value.parse_replace(input)?;
359 } else {
360 let mut new_value = Json::Null;
361 new_value.parse_replace(input)?;
362
363 self.0.push((key, new_value));
364 }
365
366 Ok(())
367 }
368
369 fn parse_object_in_place<I>(
370 &mut self,
371 chars: &mut Peekable<I>,
372 input: &'a str,
373 ) -> Result<(), ParseError>
374 where
375 I: Iterator<Item = (usize, char)>,
376 {
377 let Some((_, '{')) = chars.next() else {
379 return Err(ParseError {
380 message: "Object doesn't have a starting brace",
381 value: input.to_owned(),
382 index: 0,
383 });
384 };
385
386 skip_whitespace(chars);
387 if let Some((_, '}')) = chars.peek() {
388 chars.next(); for (_, value) in self.iter_mut() {
392 value.replace_with_null();
393 }
394
395 return Ok(());
396 }
397
398 let mut count = 0;
399
400 loop {
401 let Ok(Json::String(key)) = parse_string(chars, input) else {
402 return Err(ParseError {
403 message: "Unexpected char in object",
404 value: input.to_owned(),
405 index: chars
406 .peek()
407 .map(|&(i, _)| i - 1)
408 .unwrap_or_else(|| input.len() - 1),
409 });
410 };
411
412 skip_whitespace(chars);
413 if chars.next().map(|(_, c)| c) != Some(':') {
414 return Err(ParseError {
415 message: "Expected colon ':' after key in object",
416 value: input.to_owned(),
417 index: chars
420 .peek()
421 .map(|&(i, _)| i - 1)
422 .unwrap_or_else(|| input.len() - 1),
423 });
424 }
425
426 skip_whitespace(chars);
427 if let Some((old_key, value)) = self.0.get_mut(count) {
428 *old_key = key;
429 value.parse_value_in_place(chars, input)?;
430 } else {
431 let mut new_value = Json::Null;
432 new_value.parse_value_in_place(chars, input)?;
433 self.0.push((key, new_value));
434 }
435
436 count += 1;
437
438 skip_whitespace(chars);
439 match chars.peek().map(|&(_, c)| c) {
440 Some(',') => {
441 chars.next();
442 skip_whitespace(chars);
443 } Some('}') => {
445 chars.next(); for (_, value) in self.iter_mut().skip(count) {
448 value.replace_with_null();
449 }
450
451 return Ok(());
452 }
453 _ => {
454 return Err(ParseError {
455 message: "Expected comma or closing brace '}' in \
456 object",
457 value: input.to_owned(),
458 index: chars.peek().map(|&(i, _)| i).unwrap_or_else(|| input.len()),
459 })
460 }
461 }
462 }
463 }
464}
465
466fn parse_array_in_place<'a, I>(
467 arr: &mut Vec<Json<'a>>,
468 chars: &mut Peekable<I>,
469 input: &'a str,
470) -> Result<(), ParseError>
471where
472 I: Iterator<Item = (usize, char)>,
473{
474 chars.next(); skip_whitespace(chars);
477 if let Some((_, ']')) = chars.peek() {
478 chars.next(); for value in arr.iter_mut() {
481 value.replace_with_null();
482 }
483
484 return Ok(());
485 }
486
487 let mut count = 0;
488
489 loop {
490 if count < arr.len() {
491 arr[count].parse_value_in_place(chars, input)?;
492 } else {
493 let mut new_element = Json::Null;
494 new_element.parse_value_in_place(chars, input)?;
495 arr.push(new_element);
496 }
497 count += 1;
498
499 skip_whitespace(chars);
500 match chars.peek().map(|&(_, c)| c) {
501 Some(',') => {
502 chars.next();
503 skip_whitespace(chars);
504 } Some(']') => {
506 chars.next(); for value in arr.iter_mut().skip(count) {
509 value.replace_with_null();
510 }
511
512 return Ok(());
513 } _ => {
515 return Err(ParseError {
516 message: "Expected comma or closing bracket ']' in array",
517 value: input.to_owned(),
518 index: chars
520 .peek()
521 .map(|&(i, _)| i)
522 .unwrap_or_else(|| input.len() - 1),
523 });
524 }
525 }
526 }
527}
528
529fn parse_string<'a, I>(chars: &mut Peekable<I>, input: &'a str) -> Result<Json<'a>, ParseError>
530where
531 I: Iterator<Item = (usize, char)>,
532{
533 let Some((start_index, '"')) = chars.next() else {
535 return Err(ParseError {
536 message: "Expected opening quote for string",
537 value: input.to_owned(),
538 index: input.len(),
539 });
540 };
541
542 while let Some((i, c)) = chars.next() {
543 match c {
544 '"' => return Ok(Json::String(&input[start_index + 1..i])),
545 '\\' => {
546 chars.next(); }
548 _ => {}
549 }
550 }
551
552 Err(ParseError {
553 message: "Closing quote not found for string started",
554 value: input.to_owned(),
555 index: start_index,
556 })
557}
558
559fn parse_null<'a, I>(chars: &mut Peekable<I>, input: &'a str) -> Result<Json<'a>, ParseError>
560where
561 I: Iterator<Item = (usize, char)>,
562{
563 let start_index = chars.peek().map(|&(i, _)| i).unwrap_or_else(|| input.len());
564 if chars.next().map(|(_, c)| c) == Some('n')
565 && chars.next().map(|(_, c)| c) == Some('u')
566 && chars.next().map(|(_, c)| c) == Some('l')
567 && chars.next().map(|(_, c)| c) == Some('l')
568 {
569 Ok(Json::Null)
570 } else {
571 Err(ParseError {
572 message: "Invalid null value",
573 value: input.to_owned(),
574 index: start_index,
576 })
577 }
578}
579
580fn parse_raw_value<'a, I>(chars: &mut Peekable<I>, input: &'a str) -> Result<Json<'a>, ParseError>
581where
582 I: Iterator<Item = (usize, char)>,
583{
584 let start_index = chars.peek().map(|&(i, _)| i).unwrap_or_else(|| input.len());
585 while let Some(&(i, c)) = chars.peek() {
586 if c == ',' || c == ']' || c == '}' {
587 return Ok(Json::Value(&input[start_index..i]));
588 }
589 chars.next();
590 }
591
592 Ok(Json::Value(&input[start_index..]))
593}
594
595fn skip_whitespace<I>(chars: &mut Peekable<I>)
597where
598 I: Iterator<Item = (usize, char)>,
599{
600 while let Some(&(_, c)) = chars.peek() {
601 if c.is_whitespace() {
602 chars.next();
603 } else {
604 break;
605 }
606 }
607}
608
609impl Json<'_> {
610 pub fn indented(&self, indent: usize) -> StyledJson {
611 StyledJson {
612 json: self,
613 indent,
614 styles: None,
615 }
616 }
617
618 pub fn styled(&self, styles: MarkupStyles) -> StyledJson {
619 StyledJson {
620 json: self,
621 indent: 0,
622 styles: Some(styles),
623 }
624 }
625}
626
627pub struct StyledJson<'a> {
628 json: &'a Json<'a>,
629 indent: usize,
630 styles: Option<MarkupStyles>,
631}
632
633impl StyledJson<'_> {
634 pub fn indented(self, indent: usize) -> Self { Self { indent, ..self } }
635
636 pub fn styled(self, styles: MarkupStyles) -> Self {
637 Self {
638 styles: Some(styles),
639 ..self
640 }
641 }
642}
643
644impl fmt::Display for StyledJson<'_> {
645 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
646 self.json.fmt_compact(f, &self.styles)
647 }
648}
649
650impl fmt::Debug for StyledJson<'_> {
651 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
652 self.json.fmt_pretty(f, self.indent, &self.styles)
653 }
654}
655
656#[derive(Debug, Clone, Copy, PartialEq)]
657pub struct MarkupStyles {
658 pub key: Style,
659 pub value: Style,
660 pub str: Style,
661 pub syntax: Style,
662}
663
664impl Default for MarkupStyles {
665 fn default() -> Self {
666 Self {
667 key: Style::new().fg::<Blue>(),
668 value: Style::new().fg::<BrightWhite>(),
669 str: Style::new().fg::<Green>(),
670 syntax: Style::new().fg::<White>(),
671 }
672 }
673}
674
675impl fmt::Display for Json<'_> {
676 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
677 self.fmt_compact(f, &None)
678 }
679}
680
681impl fmt::Debug for Json<'_> {
682 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
683 self.fmt_pretty(f, 0, &None)
684 }
685}
686
687impl Json<'_> {
688 fn fmt_compact(
689 &self,
690 f: &mut fmt::Formatter<'_>,
691 styles: &Option<MarkupStyles>,
692 ) -> Result<(), fmt::Error> {
693 match self {
694 Json::Object(obj) => {
695 if obj.is_empty() {
696 return write_syntax(f, "{}", styles);
697 }
698
699 let mut non_nulls = obj.iter().filter(|(_, v)| !v.is_null());
700 let Some((key, value)) = non_nulls.next() else {
701 return write_syntax(f, "{}", styles);
702 };
703
704 write_syntax(f, "{", styles)?;
705 write_key(f, key, styles)?;
706 write_syntax(f, ":", styles)?;
707 value.fmt_compact(f, styles)?;
708
709 for (key, value) in non_nulls {
710 write_syntax(f, ",", styles)?;
711 write_key(f, key, styles)?;
712 write_syntax(f, ":", styles)?;
713 value.fmt_compact(f, styles)?;
714 }
715
716 write_syntax(f, "}", styles)
717 }
718 Json::Array(arr) => {
719 if arr.is_empty() {
720 return write_syntax(f, "[]", styles);
721 }
722
723 let mut non_nulls = arr.iter().filter(|v| !v.is_null());
724 let Some(value) = non_nulls.next() else {
725 return write_syntax(f, "[]", styles);
726 };
727
728 write_syntax(f, "[", styles)?;
729 value.fmt_compact(f, styles)?;
730
731 for value in non_nulls {
732 write_syntax(f, ",", styles)?;
733 value.fmt_compact(f, styles)?;
734 }
735 write_syntax(f, "]", styles)
736 }
737 Json::String(v) => write_str(f, v, styles),
738 Json::Value(v) => write_value(f, v, styles),
739 Json::Null | Json::NullPrevObject(_) | Json::NullPrevArray(_) => {
740 write_value(f, "null", styles)
741 }
742 }
743 }
744
745 fn fmt_pretty(
746 &self,
747 f: &mut fmt::Formatter<'_>,
748 indent: usize,
749 styles: &Option<MarkupStyles>,
750 ) -> Result<(), fmt::Error> {
751 match self {
752 Json::Object(obj) => {
753 if obj.is_empty() {
754 return write_syntax(f, "{}", styles);
755 }
756
757 let mut non_nulls = obj.iter().filter(|(_, v)| !v.is_null());
758 let Some((key, value)) = non_nulls.next() else {
759 return write_syntax(f, "{}", styles);
760 };
761
762 write_syntax(f, "{", styles)?;
763 write!(f, "\n{:indent$}", "", indent = (indent + 2))?;
764 write_key(f, key, styles)?;
765 write_syntax(f, ":", styles)?;
766 write!(f, " ")?;
767 value.fmt_pretty(f, indent + 2, styles)?;
768
769 for (key, value) in non_nulls {
770 write_syntax(f, ",", styles)?;
771 write!(f, "\n{:indent$}", "", indent = (indent + 2))?;
772 write_key(f, key, styles)?;
773 write_syntax(f, ":", styles)?;
774 write!(f, " ")?;
775 value.fmt_pretty(f, indent + 2, styles)?;
776 }
777
778 write!(f, "\n{:indent$}", "", indent = indent)?;
779 write_syntax(f, "}", styles)
780 }
781 Json::Array(arr) => {
782 if arr.is_empty() {
783 return write_syntax(f, "[]", styles);
784 }
785
786 let mut non_nulls = arr.iter().filter(|v| !v.is_null());
787 let Some(value) = non_nulls.next() else {
788 return write_syntax(f, "[]", styles);
789 };
790
791 write_syntax(f, "[", styles)?;
792 write!(f, "\n{:indent$}", "", indent = (indent + 2))?;
793 value.fmt_pretty(f, indent + 2, styles)?;
794
795 for value in non_nulls {
796 write_syntax(f, ",", styles)?;
797 write!(f, "\n{:indent$}", "", indent = (indent + 2))?;
798 value.fmt_pretty(f, indent + 2, styles)?;
799 }
800 write!(f, "\n{:indent$}", "", indent = indent)?;
801 write_syntax(f, "]", styles)
802 }
803 Json::String(v) => write_str(f, v, styles),
804 Json::Value(v) => write_value(f, v, styles),
805 Json::Null | Json::NullPrevObject(_) | Json::NullPrevArray(_) => {
806 write_value(f, "null", styles)
807 }
808 }
809 }
810}
811
812fn write_key(
813 f: &mut fmt::Formatter<'_>,
814 key: &str,
815 styles: &Option<MarkupStyles>,
816) -> Result<(), fmt::Error> {
817 if let Some(style) = styles {
818 write!(f, "{}", format_args!("\"{key}\"").style(style.key))
819 } else {
820 write!(f, "\"{}\"", key)
821 }
822}
823
824fn write_value(
825 f: &mut fmt::Formatter<'_>,
826 value: &str,
827 styles: &Option<MarkupStyles>,
828) -> Result<(), fmt::Error> {
829 if let Some(style) = styles {
830 write!(f, "{}", value.style(style.value))
831 } else {
832 write!(f, "{}", value)
833 }
834}
835
836fn write_str(
837 f: &mut fmt::Formatter<'_>,
838 str: &str,
839 styles: &Option<MarkupStyles>,
840) -> Result<(), fmt::Error> {
841 if let Some(style) = styles {
842 write!(f, "{}", format_args!("\"{str}\"").style(style.str))
843 } else {
844 write!(f, "\"{}\"", str)
845 }
846}
847
848fn write_syntax(
849 f: &mut fmt::Formatter<'_>,
850 syntax: &str,
851 styles: &Option<MarkupStyles>,
852) -> Result<(), fmt::Error> {
853 if let Some(style) = styles {
854 write!(f, "{}", syntax.style(style.syntax))
855 } else {
856 write!(f, "{}", syntax)
857 }
858}
859
860fn parse_index(s: &str) -> Option<usize> {
861 if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) {
862 return None;
863 }
864 s.parse().ok()
865}
866
867pub struct ParseError {
868 pub message: &'static str,
869 pub value: String,
870 pub index: usize,
871}
872
873impl std::fmt::Display for ParseError {
874 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
875 let start = self.index.saturating_sub(15);
878 let end = (self.index + 10).min(self.value.len());
879 let snippet = &self.value[start..end];
880
881 write!(f, "{} at index {}: '{}'", self.message, self.index, snippet)
882 }
883}
884
885impl std::fmt::Debug for ParseError {
886 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
887 let snippet_length = 20;
888 let start = self.index.saturating_sub(snippet_length);
889 let end = (self.index + snippet_length).min(self.value.len());
890 let snippet = &self.value[start..end];
891
892 let caret_position = self.index.saturating_sub(start) + 1;
893
894 write!(
895 f,
896 "{} at index {}:\n`{}`\n{:>width$}",
897 self.message,
898 self.index,
899 snippet,
900 "^", width = caret_position + 1, )
903 }
904}
905impl std::error::Error for ParseError {}
906
907#[cfg(test)]
908mod tests {
909 use super::*;
910
911 #[test]
912 fn basic() {
913 let test_cases = vec![
914 r#"{"key": "value"}"#,
915 r#"{"escaped": "This is a \"test\""}"#,
916 r#"{"nested": {"array": [1, "two", null], "emptyObj": {}, "bool": true}}"#,
917 r#"["mixed", 123, {"obj": "inside array"}]"#,
918 r#"{}"#,
919 r#"[]"#,
920 ];
921
922 for case in test_cases {
923 match parse_json(case) {
924 Ok(parsed) => println!("Parsed JSON: {:#?}", parsed),
925 Err(e) => println!("Failed to parse JSON: {}", e),
926 }
927 }
928
929 let arr = parse_json(r#"["mixed", 123, {"obj": "inside array"}]"#).unwrap();
930 println!("Array: {:#?}", arr);
931 assert_eq!(arr.get_i(2).get("obj").as_value(), Some("\"inside array\""));
932 }
933
934 #[test]
935 fn invalid() {
936 let test_cases = vec![
937 (
938 r#"{"key": "value" "#,
939 "Missing Closing Brace for an Object",
940 ),
941 (
942 r#"{"key": "value }"#,
943 "Missing Closing Quote for a String",
944 ),
945 (r#"{"key" , "value"}"#, "Missing Colon in an Object"),
946 (
947 r#"{"key1": "value1", "key2": "value2" , }"#,
948 "Extra Comma in an Object",
949 ),
950 (r#"{key: "value"}"#, "Unquoted Key"),
951 (
952 r#"{"array": [1, 2, "missing bracket" , } "#,
953 "Unclosed Array",
954 ),
955 ];
956
957 for (json_str, description) in test_cases {
958 println!("Testing case: {}", description);
959 match parse_json(json_str) {
960 Ok(_) => println!("No error detected, but expected an error."),
961 Err(e) => {
962 println!("Error (Display): {}", e);
963 println!("Error (Debug):\n{:?}", e);
964 }
965 }
966 println!("---------------------------------------\n");
967 }
968 }
969}