jlf/
json.rs

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    // first arg is the key value pairs, second is a list of keys used as
18    // cache for parse_replace
19    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    /// Looks up a value by a JSON Pointer.
89    ///
90    /// JSON Pointer defines a string syntax for identifying a specific value
91    /// within a JavaScript Object Notation (JSON) document.
92    ///
93    /// A Pointer is a Unicode string with the reference tokens separated by
94    /// `/`. Inside tokens `/` is replaced by `~1` and `~` is replaced by
95    /// `~0`. The addressed value is returned and if there is no such value
96    /// `None` is returned.
97    ///
98    /// For more information read [RFC6901](https://tools.ietf.org/html/rfc6901).
99    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    /// Looks up a value by a JSON Pointer and returns a mutable reference to
118    /// that value.
119    ///
120    /// JSON Pointer defines a string syntax for identifying a specific value
121    /// within a JavaScript Object Notation (JSON) document.
122    ///
123    /// A Pointer is a Unicode string with the reference tokens separated by
124    /// `/`. Inside tokens `/` is replaced by `~1` and `~` is replaced by
125    /// `~0`. The addressed value is returned and if there is no such value
126    /// `None` is returned.
127    ///
128    /// For more information read [RFC6901](https://tools.ietf.org/html/rfc6901).
129    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    // Replace self with a new value and return the previous value
216    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        // Consume the opening '{'
378        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(); // Consume the closing '}'
389
390            // Set values to Json::Null for keys not found in the input
391            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                    // Use the index right after the key, which should be the
418                    // current position
419                    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                } // Consume and continue
444                Some('}') => {
445                    chars.next(); // Consume the closing '}'
446
447                    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(); // Consume the opening '['
475
476    skip_whitespace(chars);
477    if let Some((_, ']')) = chars.peek() {
478        chars.next(); // Consume the closing ']'
479
480        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            } // Consume and continue
505            Some(']') => {
506                chars.next(); // Consume the closing ']'
507
508                for value in arr.iter_mut().skip(count) {
509                    value.replace_with_null();
510                }
511
512                return Ok(());
513            } // Handle in the next loop iteration
514            _ => {
515                return Err(ParseError {
516                    message: "Expected comma or closing bracket ']' in array",
517                    value: input.to_owned(),
518                    // Use the current position as the error index
519                    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    // Consume the opening quote
534    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(); // Skip the character following the escape
547            }
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            // Point to the start of 'n' that led to expecting "null"
575            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
595// skip whitespaces and return the number of characters skipped
596fn 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        // Create a snippet from the input, showing up to 10 characters before
876        // and after the error index
877        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            "^",                        // Caret pointing to the error location
901            width = caret_position + 1, // Correct alignment for the caret
902        )
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}