Skip to content

Commit

Permalink
resolves duplication of errors in miette
Browse files Browse the repository at this point in the history
  • Loading branch information
chanced committed Jan 30, 2025
1 parent 6ff66a8 commit 1996c1a
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 234 deletions.
128 changes: 24 additions & 104 deletions src/assign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
//!
use crate::{
diagnostic::{impl_diagnostic_url, Diagnostic, Label},
diagnostic::{diagnostic_url, Diagnostic, Label},
index::{OutOfBoundsError, ParseIndexError},
Pointer, PointerBuf,
};
Expand All @@ -47,16 +47,6 @@ use core::{
iter::once,
};

/*
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
╔══════════════════════════════════════════════════════════════════════════════╗
║ ║
║ Assign ║
║ ¯¯¯¯¯¯¯¯ ║
╚══════════════════════════════════════════════════════════════════════════════╝
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
*/

/// Implemented by types which can internally assign a
/// ([`Value`](`Assign::Value`)) at a path represented by a JSON [`Pointer`].
///
Expand Down Expand Up @@ -134,30 +124,10 @@ pub trait Assign {
V: Into<Self::Value>;
}

/*
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
╔══════════════════════════════════════════════════════════════════════════════╗
║ ║
║ AssignError ║
║ ¯¯¯¯¯¯¯¯¯¯¯¯¯ ║
╚══════════════════════════════════════════════════════════════════════════════╝
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
*/

/// Alias for [`Error`] - indicates a value assignment failed.
#[deprecated(since = "0.7.0", note = "renamed to `Error`")]
pub type AssignError = Error;

/*
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
╔══════════════════════════════════════════════════════════════════════════════╗
║ ║
║ Error ║
║ ¯¯¯¯¯¯¯ ║
╚══════════════════════════════════════════════════════════════════════════════╝
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
*/

/// Possible error returned from [`Assign`] implementations for
/// [`serde_json::Value`] and
/// [`toml::Value`](https://docs.rs/toml/0.8.14/toml/index.html).
Expand Down Expand Up @@ -207,32 +177,20 @@ impl Error {

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::FailedToParseIndex { .. } => {
write!(
f,
"value failed to be assigned by json pointer; \
array index for token at offset {} is not a valid integer or '-'",
self.offset()
)
}
Self::OutOfBounds { .. } => {
write!(
f,
"value failed to be assigned by json pointer; \
array index for token at offset {} is out of bounds",
self.offset()
)
}
}
write!(
f,
"value failed to be assigned, caused by token (position: {}, offset: {}) of the json pointer",
self.position(),
self.offset()
)
}
}

impl Diagnostic for Error {
type Subject = PointerBuf;

fn url() -> &'static str {
impl_diagnostic_url!(enum assign::Error)
diagnostic_url!(enum assign::Error)
}

fn labels(&self, origin: &Self::Subject) -> Option<Box<dyn Iterator<Item = Label>>> {
Expand All @@ -244,18 +202,22 @@ impl Diagnostic for Error {
self.offset()
};
let len = token.encoded().len();
Some(match self {
Error::FailedToParseIndex { .. } => Box::new(once(Label::new(
format!("\"{}\" is an invalid array index", token.decoded()),
offset,
len,
))),
Error::OutOfBounds { source, .. } => Box::new(once(Label::new(
format!("{} is out of bounds (len: {})", source.index, source.length),
offset,
len,
))),
})
let text = match self {
Error::FailedToParseIndex { .. } => {
format!("expected array index or '-', found \"{}\"", token.decoded())
}
Error::OutOfBounds { source, .. } => {
format!("{} is out of bounds (len: {})", source.index, source.length)
}
};
Some(Box::new(once(Label::new(text, offset, len))))
}
}

#[cfg(feature = "miette")]
impl miette::Diagnostic for Error {
fn url<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
Some(Box::new(<Self as Diagnostic>::url()))
}
}

Expand All @@ -269,16 +231,6 @@ impl std::error::Error for Error {
}
}

/*
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
╔══════════════════════════════════════════════════════════════════════════════╗
║ ║
║ json impl ║
║ ¯¯¯¯¯¯¯¯¯¯¯ ║
╚══════════════════════════════════════════════════════════════════════════════╝
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
*/

#[cfg(feature = "json")]
mod json {
use super::{Assign, Assigned, Error};
Expand Down Expand Up @@ -454,16 +406,6 @@ mod json {
}
}

/*
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
╔══════════════════════════════════════════════════════════════════════════════╗
║ ║
║ toml impl ║
║ ¯¯¯¯¯¯¯¯¯¯¯ ║
╚══════════════════════════════════════════════════════════════════════════════╝
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
*/

#[cfg(feature = "toml")]
mod toml {
use super::{Assign, Assigned, Error};
Expand Down Expand Up @@ -638,16 +580,6 @@ enum Assigned<'v, V> {
Continue { next_dest: &'v mut V, same_value: V },
}

/*
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
╔══════════════════════════════════════════════════════════════════════════════╗
║ ║
║ Tests ║
║ ¯¯¯¯¯¯¯ ║
╚══════════════════════════════════════════════════════════════════════════════╝
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
*/

#[cfg(test)]
#[allow(clippy::too_many_lines)]
mod tests {
Expand Down Expand Up @@ -694,12 +626,6 @@ mod tests {
}
}

/*
╔═══════════════════════════════════════════════════╗
║ json ║
╚═══════════════════════════════════════════════════╝
*/

#[test]
#[cfg(feature = "json")]
fn assign_json() {
Expand Down Expand Up @@ -890,12 +816,6 @@ mod tests {
.for_each(|(i, t)| t.run(i));
}

/*
╔══════════════════════════════════════════════════╗
║ toml ║
╚══════════════════════════════════════════════════╝
*/

#[test]
#[cfg(feature = "toml")]
fn assign_toml() {
Expand Down
32 changes: 25 additions & 7 deletions src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ where
D::Subject: fmt::Debug,
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.source)
self.source.source()
}
}

Expand All @@ -116,18 +116,18 @@ where
}
}

macro_rules! impl_diagnostic_url {
macro_rules! diagnostic_url {
(enum $type:ident) => {
$crate::diagnostic::impl_diagnostic_url!("enum", "", $type)
$crate::diagnostic::diagnostic_url!("enum", "", $type)
};
(struct $type:ident) => {
$crate::diagnostic::impl_diagnostic_url!("struct", "", $type)
$crate::diagnostic::diagnostic_url!("struct", "", $type)
};
(enum $mod:ident::$type:ident) => {
$crate::diagnostic::impl_diagnostic_url!("enum", concat!("/", stringify!($mod)), $type)
$crate::diagnostic::diagnostic_url!("enum", concat!("/", stringify!($mod)), $type)
};
(struct $mod:ident::$type:ident) => {
$crate::diagnostic::impl_diagnostic_url!("struct", concat!("/", stringify!($mod)), $type)
$crate::diagnostic::diagnostic_url!("struct", concat!("/", stringify!($mod)), $type)
};
($kind:literal, $mod:expr, $type:ident) => {
concat!(
Expand All @@ -143,7 +143,7 @@ macro_rules! impl_diagnostic_url {
)
};
}
pub(crate) use impl_diagnostic_url;
pub(crate) use diagnostic_url;

/// An extension trait for `Result<_, E>`, where `E` is an implementation of
/// [`Diagnostic`], that converts `E` into [`Report<E>`](`Report`), yielding
Expand Down Expand Up @@ -231,6 +231,24 @@ mod tests {
println!("{:?}", miette::Report::from(report));
}

#[test]
#[cfg(all(
feature = "resolve",
feature = "miette",
feature = "serde",
feature = "json"
))]
fn resolve_error() {
let v = serde_json::json!({"foo": {"bar": ["0"]}});
let ptr = PointerBuf::parse("/foo/bar/invalid/cannot/reach").unwrap();
let report = ptr.resolve(&v).diagnose(ptr).unwrap_err();
println!("{:?}", miette::Report::from(report));

let ptr = PointerBuf::parse("/foo/bar/3/cannot/reach").unwrap();
let report = ptr.resolve(&v).diagnose(ptr).unwrap_err();
println!("{:?}", miette::Report::from(report));
}

#[test]
fn parse_error() {
let invalid = "/foo/bar/invalid~3~encoding/cannot/reach";
Expand Down
14 changes: 8 additions & 6 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ derive_try_from!(String, &String);
*/

/// Indicates that an `Index` is not within the given bounds.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OutOfBoundsError {
/// The provided array length.
///
Expand Down Expand Up @@ -276,7 +276,7 @@ impl std::error::Error for OutOfBoundsError {}
*/

/// Indicates that the `Token` could not be parsed as valid RFC 6901 array index.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParseIndexError {
/// The Token does not represent a valid integer.
InvalidInteger(ParseIntError),
Expand All @@ -295,14 +295,16 @@ impl From<ParseIntError> for ParseIndexError {
impl fmt::Display for ParseIndexError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ParseIndexError::InvalidInteger(source) => {
write!(f, "failed to parse token as an integer: {source}")
ParseIndexError::InvalidInteger(_) => {
write!(f, "failed to parse token as an integer")
}
ParseIndexError::LeadingZeros => write!(
f,
"token contained leading zeros, which are disallowed by RFC 6901"
),
ParseIndexError::InvalidCharacter(err) => err.fmt(f),
ParseIndexError::InvalidCharacter(_) => {
write!(f, "failed to parse token as an index")
}
}
}
}
Expand All @@ -319,7 +321,7 @@ impl std::error::Error for ParseIndexError {
}

/// Indicates that a non-digit character was found when parsing the RFC 6901 array index.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvalidCharacterError {
pub(crate) source: String,
pub(crate) offset: usize,
Expand Down
Loading

0 comments on commit 1996c1a

Please sign in to comment.