json_parse/
data.rs

1/* Data models */
2
3use std::fmt::Display;
4
5/// A representation of a JSON element.
6#[derive(Debug, Clone, Default, PartialEq)]
7pub enum JsonElement {
8    /// A literal `null` value
9    #[default]
10    Null,
11    /// A boolean value (`true` / `false`)
12    Boolean(bool),
13    /// A numeric value
14    Number(f64),
15    /// A string value. Escape characters and sequences have already been parsed in the contained [String].
16    String(String),
17    /// An array containing any number of other JSON elements.
18    Array(Vec<JsonElement>),
19    /// A JSON object, consisting of a series of key-value pairs.
20    ///
21    /// The pairs are represented using a [Vec] and are provided in the same order in which they are
22    /// defined in the original source.
23    ///
24    /// The [String] keys within a [JsonElement::Object] are guaranteed to be unique.
25    Object(Vec<(String, JsonElement)>),
26}
27
28/// Returned when a JSON string is malformed or contains any errors.
29#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct ParseError {
31    /// User-friendly description of the error.
32    pub msg: String,
33    /// 1-based index of the line within the source JSON string in which the error occured.
34    pub line: usize,
35    /// 0-based index of the column within the line where the error occured.
36    pub column: usize,
37}
38
39#[derive(Debug, Clone, PartialEq)]
40pub struct JsonToken {
41    pub kind: TokenKind,
42    pub pos: TokenPosition,
43}
44
45#[derive(Debug, Clone, PartialEq)]
46pub enum TokenKind {
47    LeftBrace,
48    RightBrace,
49    LeftBracket,
50    RightBracket,
51    Comma,
52    Colon,
53    True,
54    False,
55    Null,
56    Number(f64),
57    String(String),
58    Eof,
59}
60
61#[derive(Debug, Clone, Copy, PartialEq)]
62pub struct TokenPosition {
63    pub line: usize,
64    pub column: usize,
65}
66
67impl ParseError {
68    pub fn new(msg: String, line: usize, column: usize) -> Self {
69        Self { msg, line, column }
70    }
71}
72
73impl Display for TokenKind {
74    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75        match self {
76            TokenKind::LeftBrace => f.write_str("'{'"),
77            TokenKind::RightBrace => f.write_str("'}'"),
78            TokenKind::LeftBracket => f.write_str("'['"),
79            TokenKind::RightBracket => f.write_str("']'"),
80            TokenKind::Comma => f.write_str("','"),
81            TokenKind::Colon => f.write_str("':'"),
82            TokenKind::True => f.write_str("boolean (true)"),
83            TokenKind::False => f.write_str("boolean (false)"),
84            TokenKind::Null => f.write_str("null"),
85            TokenKind::Number(n) => f.write_str(&format!("number ({n})")),
86            TokenKind::String(s) => f.write_str(&format!("string (\"{s}\")")),
87            TokenKind::Eof => f.write_str("end-of-file"),
88        }
89    }
90}
91
92impl JsonToken {
93    pub const fn dummy() -> Self {
94        let pos = TokenPosition { column: 0, line: 0 };
95        let kind = TokenKind::Null;
96        Self { pos, kind }
97    }
98
99    pub fn get_string(self) -> String {
100        /* Consumes a String-kind token to return the String inside it.
101        Will panic if called on a non-string token. */
102        match self.kind {
103            TokenKind::String(s) => s,
104            _ => panic!("Tried to extract a string from an invalid token"),
105        }
106    }
107}
108
109impl TokenKind {
110    pub fn same_kind(&self, other: &Self) -> bool {
111        core::mem::discriminant(self) == core::mem::discriminant(other)
112    }
113}
114
115impl Default for TokenPosition {
116    fn default() -> Self {
117        Self { line: 1, column: 0 }
118    }
119}