Coverage Report

Created: 2026-10-28 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/jsonc-parser-0.34.0/src/errors.rs
Line
Count
Source
1
use std::fmt;
2
3
use crate::ParseStringErrorKind;
4
5
use super::common::Range;
6
7
#[derive(Debug)]
8
pub enum ParseErrorKind {
9
  BareDecimalPointNumbersNotAllowed,
10
  CommentsNotAllowed,
11
  ExpectedColonAfterObjectKey,
12
  ExpectedObjectValue,
13
  ExpectedDigit,
14
  ExpectedDigitFollowingNegativeSign,
15
  ExpectedPlusMinusOrDigitInNumberLiteral,
16
  ExpectedStringObjectProperty,
17
  HexadecimalNumbersNotAllowed,
18
  ExpectedComma,
19
  MultipleRootJsonValues,
20
  NonFiniteNumbersNotAllowed,
21
  SingleQuotedStringsNotAllowed,
22
  String(ParseStringErrorKind),
23
  TrailingCommasNotAllowed,
24
  UnaryPlusNumbersNotAllowed,
25
  UnexpectedCloseBrace,
26
  UnexpectedCloseBracket,
27
  UnexpectedColon,
28
  UnexpectedComma,
29
  UnexpectedToken,
30
  UnexpectedTokenInObject,
31
  UnexpectedWord,
32
  UnterminatedArray,
33
  UnterminatedCommentBlock,
34
  UnterminatedObject,
35
  NestingDepthExceeded,
36
  /// Custom error message, used by the serde deserializer.
37
  #[cfg(feature = "serde")]
38
  Custom(String),
39
}
40
41
impl std::fmt::Display for ParseErrorKind {
42
0
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43
    use ParseErrorKind::*;
44
0
    match self {
45
      BareDecimalPointNumbersNotAllowed => {
46
0
        write!(f, "Leading or trailing decimal points on numbers are not allowed")
47
      }
48
      CommentsNotAllowed => {
49
0
        write!(f, "Comments are not allowed")
50
      }
51
      ExpectedColonAfterObjectKey => {
52
0
        write!(f, "Expected colon after the string or word in object property")
53
      }
54
      ExpectedDigit => {
55
0
        write!(f, "Expected digit")
56
      }
57
      ExpectedDigitFollowingNegativeSign => {
58
0
        write!(f, "Expected digit following negative sign")
59
      }
60
      ExpectedPlusMinusOrDigitInNumberLiteral => {
61
0
        write!(f, "Expected plus, minus, or digit in number literal")
62
      }
63
      ExpectedObjectValue => {
64
0
        write!(f, "Expected value after colon in object property")
65
      }
66
      ExpectedStringObjectProperty => {
67
0
        write!(f, "Expected string for object property")
68
      }
69
      HexadecimalNumbersNotAllowed => {
70
0
        write!(f, "Hexadecimal numbers are not allowed")
71
      }
72
      ExpectedComma => {
73
0
        write!(f, "Expected comma")
74
      }
75
      MultipleRootJsonValues => {
76
0
        write!(f, "Text cannot contain more than one JSON value")
77
      }
78
      NonFiniteNumbersNotAllowed => {
79
0
        write!(f, "Infinity and NaN are not allowed")
80
      }
81
      SingleQuotedStringsNotAllowed => {
82
0
        write!(f, "Single-quoted strings are not allowed")
83
      }
84
0
      String(kind) => kind.fmt(f),
85
      TrailingCommasNotAllowed => {
86
0
        write!(f, "Trailing commas are not allowed")
87
      }
88
      UnaryPlusNumbersNotAllowed => {
89
0
        write!(f, "Unary plus on numbers is not allowed")
90
      }
91
      UnexpectedCloseBrace => {
92
0
        write!(f, "Unexpected close brace")
93
      }
94
      UnexpectedCloseBracket => {
95
0
        write!(f, "Unexpected close bracket")
96
      }
97
      UnexpectedColon => {
98
0
        write!(f, "Unexpected colon")
99
      }
100
      UnexpectedComma => {
101
0
        write!(f, "Unexpected comma")
102
      }
103
      UnexpectedWord => {
104
0
        write!(f, "Unexpected word")
105
      }
106
      UnexpectedToken => {
107
0
        write!(f, "Unexpected token")
108
      }
109
      UnexpectedTokenInObject => {
110
0
        write!(f, "Unexpected token in object")
111
      }
112
      UnterminatedArray => {
113
0
        write!(f, "Unterminated array")
114
      }
115
      UnterminatedCommentBlock => {
116
0
        write!(f, "Unterminated comment block")
117
      }
118
      UnterminatedObject => {
119
0
        write!(f, "Unterminated object")
120
      }
121
      NestingDepthExceeded => {
122
0
        write!(f, "Maximum nesting depth exceeded")
123
      }
124
      #[cfg(feature = "serde")]
125
0
      Custom(msg) => write!(f, "{}", msg),
126
    }
127
0
  }
128
}
129
130
#[derive(Debug)]
131
struct ParseErrorInner {
132
  range: Range,
133
  line_display: usize,
134
  column_display: usize,
135
  kind: ParseErrorKind,
136
}
137
138
/// Error that could occur while parsing or tokenizing.
139
#[derive(Debug)]
140
pub struct ParseError(Box<ParseErrorInner>);
141
142
impl std::error::Error for ParseError {}
143
144
impl ParseError {
145
4.07k
  pub(crate) fn new(range: Range, kind: ParseErrorKind, file_text: &str) -> ParseError {
146
4.07k
    let (line_display, column_display) = get_line_and_column_display(range, file_text);
147
4.07k
    ParseError(Box::new(ParseErrorInner {
148
4.07k
      range,
149
4.07k
      line_display,
150
4.07k
      column_display,
151
4.07k
      kind,
152
4.07k
    }))
153
4.07k
  }
154
155
  /// Start and end position of the error.
156
0
  pub fn range(&self) -> Range {
157
0
    self.0.range
158
0
  }
159
160
  /// 1-indexed line number the error occurred on.
161
0
  pub fn line_display(&self) -> usize {
162
0
    self.0.line_display
163
0
  }
164
165
  /// 1-indexed column number the error occurred on.
166
  ///
167
  /// Note: Use the `error_unicode_width` feature to get the correct column
168
  /// number for Unicode characters on the line, otherwise this is just the
169
  /// number of characters by default.
170
0
  pub fn column_display(&self) -> usize {
171
0
    self.0.column_display
172
0
  }
173
174
  /// Error message.
175
0
  pub fn kind(&self) -> &ParseErrorKind {
176
0
    &self.0.kind
177
0
  }
178
179
  /// Creates an error with a custom message and no position info.
180
  #[cfg(feature = "serde")]
181
8.08k
  pub(crate) fn custom_err(msg: String) -> ParseError {
182
8.08k
    ParseError(Box::new(ParseErrorInner {
183
8.08k
      range: Range { start: 0, end: 0 },
184
8.08k
      line_display: 1,
185
8.08k
      column_display: 1,
186
8.08k
      kind: ParseErrorKind::Custom(msg),
187
8.08k
    }))
188
8.08k
  }
189
190
  /// Attaches position info to an error that doesn't have any yet.
191
  #[cfg(feature = "serde")]
192
24.1k
  pub(crate) fn with_position(mut self, range: Range, file_text: &str) -> ParseError {
193
24.1k
    if self.0.range.start == 0 && self.0.range.end == 0 {
194
5.25k
      let (line_display, column_display) = get_line_and_column_display(range, file_text);
195
5.25k
      self.0.range = range;
196
5.25k
      self.0.line_display = line_display;
197
5.25k
      self.0.column_display = column_display;
198
18.9k
    }
199
24.1k
    self
200
24.1k
  }
201
}
202
203
impl fmt::Display for ParseError {
204
0
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205
0
    let inner = &*self.0;
206
0
    write!(
207
0
      f,
208
      "{} on line {} column {}",
209
      inner.kind, inner.line_display, inner.column_display
210
    )
211
0
  }
212
}
213
214
9.32k
fn get_line_and_column_display(range: Range, file_text: &str) -> (usize, usize) {
215
9.32k
  let mut line_index = 0;
216
9.32k
  let mut column_index = 0;
217
16.6M
  for (i, c) in file_text[..range.start].char_indices() {
218
    // a lone \r ends a line comment, so it also counts as a line break here
219
16.6M
    if c == '\n' || c == '\r' && file_text.as_bytes().get(i + 1) != Some(&b'\n') {
220
67.8k
      line_index += 1;
221
67.8k
      column_index = 0;
222
67.8k
    } else {
223
      #[cfg(feature = "error_unicode_width")]
224
      {
225
        if let Some(width) = unicode_width::UnicodeWidthChar::width_cjk(c) {
226
          column_index += width;
227
        }
228
      }
229
      #[cfg(not(feature = "error_unicode_width"))]
230
16.5M
      {
231
16.5M
        column_index += 1;
232
16.5M
      }
233
    }
234
  }
235
9.32k
  (line_index + 1, column_index + 1)
236
9.32k
}