Skip to content

Commit

Permalink
migrate remaining errors to new model
Browse files Browse the repository at this point in the history
  • Loading branch information
asmello committed Feb 18, 2025
1 parent cf16365 commit c621b26
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 45 deletions.
15 changes: 3 additions & 12 deletions src/assign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -798,10 +798,7 @@ mod tests {
expected: Err(Error::FailedToParseIndex {
position: 0,
offset: 0,
source: ParseIndexError::InvalidCharacter(InvalidCharacterError {
source: "12a".into(),
offset: 2,
}),
source: ParseIndexError::InvalidCharacter(InvalidCharacterError { offset: 2 }),
}),
expected_data: json!([]),
},
Expand All @@ -823,10 +820,7 @@ mod tests {
expected: Err(Error::FailedToParseIndex {
position: 0,
offset: 0,
source: ParseIndexError::InvalidCharacter(InvalidCharacterError {
source: "+23".into(),
offset: 0,
}),
source: ParseIndexError::InvalidCharacter(InvalidCharacterError { offset: 0 }),
}),
expected_data: json!([]),
},
Expand Down Expand Up @@ -976,10 +970,7 @@ mod tests {
expected: Err(Error::FailedToParseIndex {
position: 0,
offset: 0,
source: ParseIndexError::InvalidCharacter(InvalidCharacterError {
source: "a".into(),
offset: 0,
}),
source: ParseIndexError::InvalidCharacter(InvalidCharacterError { offset: 0 }),
}),
expected_data: Value::Array(vec![]),
},
Expand Down
97 changes: 76 additions & 21 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,12 @@
//! assert_eq!(Index::Next.for_len_unchecked(30), 30);
//! ```
use crate::Token;
use crate::{
diagnostic::{diagnostic_url, IntoReport, Label},

Check failure on line 39 in src/index.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] src/index.rs#L39

error[E0432]: unresolved import `crate::diagnostic::IntoReport` --> src/index.rs:39:34 | 39 | diagnostic::{diagnostic_url, IntoReport, Label}, | ^^^^^^^^^^ no `IntoReport` in `diagnostic`
Raw output
src/index.rs:39:34:e:error[E0432]: unresolved import `crate::diagnostic::IntoReport`
  --> src/index.rs:39:34
   |
39 |     diagnostic::{diagnostic_url, IntoReport, Label},
   |                                  ^^^^^^^^^^ no `IntoReport` in `diagnostic`


__END__
Token,
};
use alloc::string::String;
use core::{fmt, num::ParseIntError, str::FromStr};
use core::{fmt, iter::once, num::ParseIntError, str::FromStr};

/// Represents an abstract index into an array.
///
Expand Down Expand Up @@ -177,7 +180,6 @@ impl FromStr for Index {
// representing a `usize` but not allowed in RFC 6901 array
// indices
Err(ParseIndexError::InvalidCharacter(InvalidCharacterError {
source: String::from(s),
offset,
}))
},
Expand Down Expand Up @@ -309,6 +311,75 @@ impl fmt::Display for ParseIndexError {
}
}

// shouldn't be used directly, but is part of a public interface
#[doc(hidden)]
#[derive(Debug)]
pub enum StringOrToken {
String(String),
Token(Token<'static>),
}

impl From<String> for StringOrToken {
fn from(value: String) -> Self {
Self::String(value)
}
}

impl From<Token<'static>> for StringOrToken {
fn from(value: Token<'static>) -> Self {
Self::Token(value)
}
}

impl core::ops::Deref for StringOrToken {
type Target = str;

fn deref(&self) -> &Self::Target {
match self {
StringOrToken::String(s) => s.as_str(),
StringOrToken::Token(t) => t.encoded(),
}
}
}

impl IntoReport for ParseIndexError {
type Subject = StringOrToken;

fn url() -> &'static str {
diagnostic_url!(enum ParseIndexError)
}

fn labels(
&self,
subject: &Self::Subject,
) -> Option<Box<dyn Iterator<Item = crate::diagnostic::Label>>> {
let subject = &**subject;
match self {
ParseIndexError::InvalidInteger(_) => None,
ParseIndexError::LeadingZeros => {
let len = subject
.chars()
.position(|c| c != '0')
.expect("starts with zeros");
let text = String::from("leading zeros");
Some(Box::new(once(Label::new(text, 0, len))))
}
ParseIndexError::InvalidCharacter(err) => {
let len = subject
.chars()
.skip(err.offset)
.position(|c| !c.is_ascii_digit())
.expect("at least one non-digit char");
let text = String::from("invalid character(s)");
Some(Box::new(once(Label::new(text, err.offset, len))))
}
}
}
}

#[cfg(feature = "miette")]
impl miette::Diagnostic for ParseIndexError {}

#[cfg(feature = "std")]
impl std::error::Error for ParseIndexError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Expand All @@ -323,7 +394,6 @@ impl std::error::Error for ParseIndexError {
/// Indicates that a non-digit character was found when parsing the RFC 6901 array index.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvalidCharacterError {
pub(crate) source: String,
pub(crate) offset: usize,
}

Expand All @@ -334,29 +404,14 @@ impl InvalidCharacterError {
pub fn offset(&self) -> usize {
self.offset
}

/// Returns the source string.
pub fn source(&self) -> &str {
&self.source
}

/// Returns the offending character.
#[allow(clippy::missing_panics_doc)]
pub fn char(&self) -> char {
self.source
.chars()
.nth(self.offset)
.expect("char was found at offset")
}
}

impl fmt::Display for InvalidCharacterError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"token contains the non-digit character '{}', \
which is disallowed by RFC 6901",
self.char()
"token contains a non-digit character, \
which is disallowed by RFC 6901",
)
}
}
Expand Down
72 changes: 60 additions & 12 deletions src/token.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use core::str::Split;
use core::{iter::once, str::Split};

use crate::index::{Index, ParseIndexError};
use crate::{
diagnostic::{diagnostic_url, IntoReport, Label},

Check failure on line 4 in src/token.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] src/token.rs#L4

error[E0432]: unresolved import `crate::diagnostic::IntoReport` --> src/token.rs:4:34 | 4 | diagnostic::{diagnostic_url, IntoReport, Label}, | ^^^^^^^^^^ no `IntoReport` in `diagnostic`
Raw output
src/token.rs:4:34:e:error[E0432]: unresolved import `crate::diagnostic::IntoReport`
 --> src/token.rs:4:34
  |
4 |     diagnostic::{diagnostic_url, IntoReport, Label},
  |                                  ^^^^^^^^^^ no `IntoReport` in `diagnostic`


__END__
index::{Index, ParseIndexError},
};
use alloc::{
borrow::Cow,
fmt,
Expand Down Expand Up @@ -99,7 +102,7 @@ impl<'a> Token<'a> {
if escaped {
return Err(EncodingError {
offset: s.len(),
source: InvalidEncoding::Slash,
source: InvalidEncoding::Tilde,
});
}
Ok(Self { inner: s.into() })
Expand Down Expand Up @@ -381,13 +384,6 @@ pub struct EncodingError {
pub source: InvalidEncoding,
}

#[cfg(feature = "std")]
impl std::error::Error for EncodingError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.source)
}
}

impl fmt::Display for EncodingError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
Expand All @@ -398,6 +394,38 @@ impl fmt::Display for EncodingError {
}
}

impl IntoReport for EncodingError {
type Subject = String;

fn url() -> &'static str {
diagnostic_url!(struct EncodingError)
}

fn labels(&self, subject: &Self::Subject) -> Option<Box<dyn Iterator<Item = Label>>> {
let (text, offset) = match self.source {
InvalidEncoding::Tilde => {
if self.offset == subject.len() {
("incomplete escape sequence", self.offset - 1)
} else {
("must be 0 or 1", self.offset)
}
}
InvalidEncoding::Slash => ("invalid character", self.offset),
};
Some(Box::new(once(Label::new(text.to_string(), offset, 1))))
}
}

#[cfg(feature = "miette")]
impl miette::Diagnostic for EncodingError {}

#[cfg(feature = "std")]
impl std::error::Error for EncodingError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.source)
}
}

/*
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
╔══════════════════════════════════════════════════════════════════════════════╗
Expand Down Expand Up @@ -425,6 +453,7 @@ impl fmt::Display for InvalidEncoding {
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for InvalidEncoding {}

Expand Down Expand Up @@ -476,8 +505,27 @@ mod tests {
assert_eq!(Token::from_encoded("~0~1").unwrap().encoded(), "~0~1");
let t = Token::from_encoded("a~1b").unwrap();
assert_eq!(t.decoded(), "a/b");
assert!(Token::from_encoded("a/b").is_err());
assert!(Token::from_encoded("a~a").is_err());
assert_eq!(
Token::from_encoded("a/b"),
Err(EncodingError {
offset: 1,
source: InvalidEncoding::Slash
})
);
assert_eq!(
Token::from_encoded("a~a"),
Err(EncodingError {
offset: 2,
source: InvalidEncoding::Tilde
})
);
assert_eq!(
Token::from_encoded("a~"),
Err(EncodingError {
offset: 2,
source: InvalidEncoding::Tilde
})
);
}

#[test]
Expand Down

0 comments on commit c621b26

Please sign in to comment.