Skip to content

Commit d40db78

Browse files
committed
migrate remaining errors to new model
1 parent f3c23b9 commit d40db78

File tree

3 files changed

+139
-45
lines changed

3 files changed

+139
-45
lines changed

src/assign.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -798,10 +798,7 @@ mod tests {
798798
expected: Err(Error::FailedToParseIndex {
799799
position: 0,
800800
offset: 0,
801-
source: ParseIndexError::InvalidCharacter(InvalidCharacterError {
802-
source: "12a".into(),
803-
offset: 2,
804-
}),
801+
source: ParseIndexError::InvalidCharacter(InvalidCharacterError { offset: 2 }),
805802
}),
806803
expected_data: json!([]),
807804
},
@@ -823,10 +820,7 @@ mod tests {
823820
expected: Err(Error::FailedToParseIndex {
824821
position: 0,
825822
offset: 0,
826-
source: ParseIndexError::InvalidCharacter(InvalidCharacterError {
827-
source: "+23".into(),
828-
offset: 0,
829-
}),
823+
source: ParseIndexError::InvalidCharacter(InvalidCharacterError { offset: 0 }),
830824
}),
831825
expected_data: json!([]),
832826
},
@@ -976,10 +970,7 @@ mod tests {
976970
expected: Err(Error::FailedToParseIndex {
977971
position: 0,
978972
offset: 0,
979-
source: ParseIndexError::InvalidCharacter(InvalidCharacterError {
980-
source: "a".into(),
981-
offset: 0,
982-
}),
973+
source: ParseIndexError::InvalidCharacter(InvalidCharacterError { offset: 0 }),
983974
}),
984975
expected_data: Value::Array(vec![]),
985976
},

src/index.rs

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@
3535
//! assert_eq!(Index::Next.for_len_unchecked(30), 30);
3636
//! ```
3737
38-
use crate::Token;
38+
use crate::{
39+
diagnostic::{diagnostic_url, IntoReport, Label},
40+
Token,
41+
};
3942
use alloc::string::String;
40-
use core::{fmt, num::ParseIntError, str::FromStr};
43+
use core::{fmt, iter::once, num::ParseIntError, str::FromStr};
4144

4245
/// Represents an abstract index into an array.
4346
///
@@ -177,7 +180,6 @@ impl FromStr for Index {
177180
// representing a `usize` but not allowed in RFC 6901 array
178181
// indices
179182
Err(ParseIndexError::InvalidCharacter(InvalidCharacterError {
180-
source: String::from(s),
181183
offset,
182184
}))
183185
},
@@ -309,6 +311,75 @@ impl fmt::Display for ParseIndexError {
309311
}
310312
}
311313

314+
// shouldn't be used directly, but is part of a public interface
315+
#[doc(hidden)]
316+
#[derive(Debug)]
317+
pub enum StringOrToken {
318+
String(String),
319+
Token(Token<'static>),
320+
}
321+
322+
impl From<String> for StringOrToken {
323+
fn from(value: String) -> Self {
324+
Self::String(value)
325+
}
326+
}
327+
328+
impl From<Token<'static>> for StringOrToken {
329+
fn from(value: Token<'static>) -> Self {
330+
Self::Token(value)
331+
}
332+
}
333+
334+
impl core::ops::Deref for StringOrToken {
335+
type Target = str;
336+
337+
fn deref(&self) -> &Self::Target {
338+
match self {
339+
StringOrToken::String(s) => s.as_str(),
340+
StringOrToken::Token(t) => t.encoded(),
341+
}
342+
}
343+
}
344+
345+
impl IntoReport for ParseIndexError {
346+
type Subject = StringOrToken;
347+
348+
fn url() -> &'static str {
349+
diagnostic_url!(enum ParseIndexError)
350+
}
351+
352+
fn labels(
353+
&self,
354+
subject: &Self::Subject,
355+
) -> Option<Box<dyn Iterator<Item = crate::diagnostic::Label>>> {
356+
let subject = &**subject;
357+
match self {
358+
ParseIndexError::InvalidInteger(_) => None,
359+
ParseIndexError::LeadingZeros => {
360+
let len = subject
361+
.chars()
362+
.position(|c| c != '0')
363+
.expect("starts with zeros");
364+
let text = String::from("leading zeros");
365+
Some(Box::new(once(Label::new(text, 0, len))))
366+
}
367+
ParseIndexError::InvalidCharacter(err) => {
368+
let len = subject
369+
.chars()
370+
.skip(err.offset)
371+
.position(|c| !c.is_ascii_digit())
372+
.expect("at least one non-digit char");
373+
let text = String::from("invalid character(s)");
374+
Some(Box::new(once(Label::new(text, err.offset, len))))
375+
}
376+
}
377+
}
378+
}
379+
380+
#[cfg(feature = "miette")]
381+
impl miette::Diagnostic for ParseIndexError {}
382+
312383
#[cfg(feature = "std")]
313384
impl std::error::Error for ParseIndexError {
314385
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
@@ -323,7 +394,6 @@ impl std::error::Error for ParseIndexError {
323394
/// Indicates that a non-digit character was found when parsing the RFC 6901 array index.
324395
#[derive(Debug, Clone, PartialEq, Eq)]
325396
pub struct InvalidCharacterError {
326-
pub(crate) source: String,
327397
pub(crate) offset: usize,
328398
}
329399

@@ -334,29 +404,14 @@ impl InvalidCharacterError {
334404
pub fn offset(&self) -> usize {
335405
self.offset
336406
}
337-
338-
/// Returns the source string.
339-
pub fn source(&self) -> &str {
340-
&self.source
341-
}
342-
343-
/// Returns the offending character.
344-
#[allow(clippy::missing_panics_doc)]
345-
pub fn char(&self) -> char {
346-
self.source
347-
.chars()
348-
.nth(self.offset)
349-
.expect("char was found at offset")
350-
}
351407
}
352408

353409
impl fmt::Display for InvalidCharacterError {
354410
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
355411
write!(
356412
f,
357-
"token contains the non-digit character '{}', \
358-
which is disallowed by RFC 6901",
359-
self.char()
413+
"token contains a non-digit character, \
414+
which is disallowed by RFC 6901",
360415
)
361416
}
362417
}

src/token.rs

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
use core::str::Split;
1+
use core::{iter::once, str::Split};
22

3-
use crate::index::{Index, ParseIndexError};
3+
use crate::{
4+
diagnostic::{diagnostic_url, IntoReport, Label},
5+
index::{Index, ParseIndexError},
6+
};
47
use alloc::{
58
borrow::Cow,
69
fmt,
@@ -99,7 +102,7 @@ impl<'a> Token<'a> {
99102
if escaped {
100103
return Err(EncodingError {
101104
offset: s.len(),
102-
source: InvalidEncoding::Slash,
105+
source: InvalidEncoding::Tilde,
103106
});
104107
}
105108
Ok(Self { inner: s.into() })
@@ -381,13 +384,6 @@ pub struct EncodingError {
381384
pub source: InvalidEncoding,
382385
}
383386

384-
#[cfg(feature = "std")]
385-
impl std::error::Error for EncodingError {
386-
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
387-
Some(&self.source)
388-
}
389-
}
390-
391387
impl fmt::Display for EncodingError {
392388
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393389
write!(
@@ -398,6 +394,38 @@ impl fmt::Display for EncodingError {
398394
}
399395
}
400396

397+
impl IntoReport for EncodingError {
398+
type Subject = String;
399+
400+
fn url() -> &'static str {
401+
diagnostic_url!(struct EncodingError)
402+
}
403+
404+
fn labels(&self, subject: &Self::Subject) -> Option<Box<dyn Iterator<Item = Label>>> {
405+
let (text, offset) = match self.source {
406+
InvalidEncoding::Tilde => {
407+
if self.offset == subject.len() {
408+
("incomplete escape sequence", self.offset - 1)
409+
} else {
410+
("must be 0 or 1", self.offset)
411+
}
412+
}
413+
InvalidEncoding::Slash => ("invalid character", self.offset),
414+
};
415+
Some(Box::new(once(Label::new(text.to_string(), offset, 1))))
416+
}
417+
}
418+
419+
#[cfg(feature = "miette")]
420+
impl miette::Diagnostic for EncodingError {}
421+
422+
#[cfg(feature = "std")]
423+
impl std::error::Error for EncodingError {
424+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
425+
Some(&self.source)
426+
}
427+
}
428+
401429
/*
402430
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
403431
╔══════════════════════════════════════════════════════════════════════════════╗
@@ -425,6 +453,7 @@ impl fmt::Display for InvalidEncoding {
425453
}
426454
}
427455
}
456+
428457
#[cfg(feature = "std")]
429458
impl std::error::Error for InvalidEncoding {}
430459

@@ -476,8 +505,27 @@ mod tests {
476505
assert_eq!(Token::from_encoded("~0~1").unwrap().encoded(), "~0~1");
477506
let t = Token::from_encoded("a~1b").unwrap();
478507
assert_eq!(t.decoded(), "a/b");
479-
assert!(Token::from_encoded("a/b").is_err());
480-
assert!(Token::from_encoded("a~a").is_err());
508+
assert_eq!(
509+
Token::from_encoded("a/b"),
510+
Err(EncodingError {
511+
offset: 1,
512+
source: InvalidEncoding::Slash
513+
})
514+
);
515+
assert_eq!(
516+
Token::from_encoded("a~a"),
517+
Err(EncodingError {
518+
offset: 2,
519+
source: InvalidEncoding::Tilde
520+
})
521+
);
522+
assert_eq!(
523+
Token::from_encoded("a~"),
524+
Err(EncodingError {
525+
offset: 2,
526+
source: InvalidEncoding::Tilde
527+
})
528+
);
481529
}
482530

483531
#[test]

0 commit comments

Comments
 (0)