Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor a bit #100

Draft
wants to merge 2 commits into
base: am/new-errors
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/assign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
use crate::{
diagnostic::{impl_diagnostic_url, Diagnostic, Label},
index::{OutOfBoundsError, ParseIndexError},
Pointer,
Pointer, PointerBuf,
};
use alloc::borrow::Cow;
use core::{
Expand Down Expand Up @@ -228,8 +228,9 @@ impl fmt::Display for Error {
}
}

impl<'s> Diagnostic<'s> for Error {
type Subject = Cow<'s, Pointer>;
impl Diagnostic for Error {
type Subject = PointerBuf;
type Related = ();

fn url() -> &'static str {
impl_diagnostic_url!(enum assign::Error)
Expand Down
136 changes: 53 additions & 83 deletions src/diagnostic.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
//! Error reporting data structures and miette integration.

use core::fmt;
use core::{fmt, ops::Deref};

/// Implemented by errors which can be converted into a [`Report`].
pub trait Diagnostic<'s>: Sized + private::Sealed {
pub trait Diagnostic: Sized {
/// The value which caused the error.
type Subject: private::IntoOwned;
type Subject: Deref;

// TODO: this is here to handle multiple errors, if we choose to support it. remove if not needed.
/// Optional type of related errors for miette reporting.
///
/// This is required as this trait is not object safe. Implementations which
/// do not have related errors should use `()`.
type Related;

/// Combine the error with its subject to generate a [`Report`].
fn into_report(self, subject: impl Into<Self::Subject>) -> Report<Self, Self::Subject> {
fn into_report(self, subject: impl Into<Self::Subject>) -> Report<Self> {
Report {
source: self,
subject: subject.into(),
Expand All @@ -20,6 +27,12 @@

/// Returns the label for the given [`Subject`] if applicable.
fn labels(&self, subject: &Self::Subject) -> Option<Box<dyn Iterator<Item = Label>>>;

// TODO: this is here to handle multiple errors, if we choose to support it. remove if not needed.
// The idea is that we will need
fn related(&self) -> Option<Box<dyn Iterator<Item = Self::Related>>> {

Check warning on line 33 in src/diagnostic.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] src/diagnostic.rs#L33

warning: missing documentation for a method --> src/diagnostic.rs:33:5 | 33 | fn related(&self) -> Option<Box<dyn Iterator<Item = Self::Related>>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Raw output
src/diagnostic.rs:33:5:w:warning: missing documentation for a method
  --> src/diagnostic.rs:33:5
   |
33 |     fn related(&self) -> Option<Box<dyn Iterator<Item = Self::Related>>> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


__END__
None
}
}

/// A label for a span within a json pointer or malformed string.
Expand All @@ -46,87 +59,69 @@

/// An error wrapper which includes the subject of the failure.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Report<SRC, SUB> {
source: SRC,
subject: SUB,
pub struct Report<D: Diagnostic> {
source: D,
subject: D::Subject,
}

impl<SRC, SUB> Report<SRC, SUB> {
impl<D: Diagnostic> Report<D> {
/// The value which caused the error.
pub fn subject(&self) -> &SUB {
pub fn subject(&self) -> &<D::Subject as Deref>::Target {
&self.subject
}

/// The error which occurred.
pub fn original(&self) -> &SRC {
pub fn original(&self) -> &D {
&self.source
}

/// The original parts of the [`Report`].
pub fn decompose(self) -> (SRC, SUB) {
pub fn decompose(self) -> (D, D::Subject) {
(self.source, self.subject)
}
}

impl<'s, S> Report<S, <S as Diagnostic<'s>>::Subject>
where
S: Diagnostic<'s>,
{
/// Converts the Report into an owned instance (generally by cloning the subject).
pub fn into_owned(self) -> Report<S, <S::Subject as private::IntoOwned>::Owned> {
use private::IntoOwned;

Report {
source: self.source,
subject: self.subject.into_owned(),
}
}
}

impl<SRC, SUB> core::ops::Deref for Report<SRC, SUB> {
type Target = SRC;
impl<D: Diagnostic> core::ops::Deref for Report<D> {
type Target = D;

fn deref(&self) -> &Self::Target {
&self.source
}
}

impl<SRC, SUB> fmt::Display for Report<SRC, SUB>
where
SRC: fmt::Display,
{
impl<D: Diagnostic + fmt::Display> fmt::Display for Report<D> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
fmt::Display::fmt(&self.source, f)
}
}

#[cfg(feature = "std")]
impl<SRC, SUB> std::error::Error for Report<SRC, SUB>
impl<D> std::error::Error for Report<D>
where
SRC: fmt::Debug + std::error::Error + 'static,
SUB: fmt::Debug,
D: Diagnostic + fmt::Debug + std::error::Error + 'static,
D::Subject: fmt::Debug,
{
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
Some(&self.source)
}
}

#[cfg(feature = "miette")]
impl<'s, SRC> miette::Diagnostic for Report<SRC, SRC::Subject>
impl<D> miette::Diagnostic for Report<D>
where
SRC: Diagnostic<'s> + fmt::Debug + std::error::Error + 'static,
SRC::Subject: fmt::Debug + miette::SourceCode,
D: Diagnostic + fmt::Debug + std::error::Error + 'static,
D::Subject: fmt::Debug + miette::SourceCode,
{
fn url<'a>(&'a self) -> Option<Box<dyn core::fmt::Display + 'a>> {
Some(Box::new(SRC::url()))
Some(Box::new(D::url()))
}

fn source_code(&self) -> Option<&dyn miette::SourceCode> {
Some(&self.subject)
}

fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
Some(Box::new(SRC::labels(self, &self.subject)?.map(Into::into)))
Some(Box::new(D::labels(self, &self.subject)?.map(Into::into)))
}
}

Expand Down Expand Up @@ -160,66 +155,44 @@
pub(crate) use impl_diagnostic_url;

mod private {
use alloc::borrow::Cow;

pub trait Sealed {}
impl Sealed for crate::pointer::ParseError {}
impl Sealed for crate::assign::Error {}

pub trait IntoOwned {
type Owned;

fn into_owned(self) -> Self::Owned;
}

impl<'s, T: 'static + ToOwned + ?Sized> IntoOwned for Cow<'s, T> {
type Owned = Cow<'static, T>;

fn into_owned(self) -> Cow<'static, T> {
Cow::Owned(self.into_owned())
}
}
}

pub trait Diagnose<'s, T> {
type Error: Diagnostic<'s>;
type Error: Diagnostic;

Check warning on line 164 in src/diagnostic.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] src/diagnostic.rs#L164

warning: missing documentation for an associated type --> src/diagnostic.rs:164:5 | 164 | type Error: Diagnostic; | ^^^^^^^^^^^^^^^^^^^^^^
Raw output
src/diagnostic.rs:164:5:w:warning: missing documentation for an associated type
   --> src/diagnostic.rs:164:5
    |
164 |     type Error: Diagnostic;
    |     ^^^^^^^^^^^^^^^^^^^^^^


__END__

#[allow(clippy::missing_errors_doc)]
fn diagnose(
self,
subject: impl Into<<Self::Error as Diagnostic<'s>>::Subject>,
) -> Result<T, Report<Self::Error, <Self::Error as Diagnostic<'s>>::Subject>>;
subject: impl Into<<Self::Error as Diagnostic>::Subject>,
) -> Result<T, Report<Self::Error>>;

#[allow(clippy::missing_errors_doc)]
fn diagnose_with<F, S>(
self,
f: F,
) -> Result<T, Report<Self::Error, <Self::Error as Diagnostic<'s>>::Subject>>
fn diagnose_with<F, S>(self, f: F) -> Result<T, Report<Self::Error>>

Check warning on line 173 in src/diagnostic.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] src/diagnostic.rs#L173

warning: missing documentation for a method --> src/diagnostic.rs:173:5 | 173 | / fn diagnose_with<F, S>(self, f: F) -> Result<T, Report<Self::Error>> 174 | | where 175 | | F: FnOnce() -> S, 176 | | S: Into<<Self::Error as Diagnostic>::Subject>; | |______________________________________________________^
Raw output
src/diagnostic.rs:173:5:w:warning: missing documentation for a method
   --> src/diagnostic.rs:173:5
    |
173 | /     fn diagnose_with<F, S>(self, f: F) -> Result<T, Report<Self::Error>>
174 | |     where
175 | |         F: FnOnce() -> S,
176 | |         S: Into<<Self::Error as Diagnostic>::Subject>;
    | |______________________________________________________^


__END__
where
F: FnOnce() -> S,
S: Into<<Self::Error as Diagnostic<'s>>::Subject>;
S: Into<<Self::Error as Diagnostic>::Subject>;
}

impl<'s, T, E> Diagnose<'s, T> for Result<T, E>
where
E: Diagnostic<'s>,
E: Diagnostic,
{
type Error = E;

fn diagnose(
self,
subject: impl Into<<Self::Error as Diagnostic<'s>>::Subject>,
) -> Result<T, Report<Self::Error, <Self::Error as Diagnostic<'s>>::Subject>> {
subject: impl Into<<Self::Error as Diagnostic>::Subject>,
) -> Result<T, Report<Self::Error>> {
self.map_err(|error| error.into_report(subject.into()))
}

fn diagnose_with<F, S>(
self,
f: F,
) -> Result<T, Report<Self::Error, <Self::Error as Diagnostic<'s>>::Subject>>
fn diagnose_with<F, S>(self, f: F) -> Result<T, Report<Self::Error>>
where
F: FnOnce() -> S,
S: Into<<Self::Error as Diagnostic<'s>>::Subject>,
S: Into<<Self::Error as Diagnostic>::Subject>,
{
self.diagnose(f())
}
Expand Down Expand Up @@ -264,16 +237,13 @@

#[test]
fn into_owned() {
let owned_report = {
// creating owned string to ensure its lifetime is local
// (could also coerce a static reference, but this is less brittle)
let invalid = "/foo/bar/invalid~3~encoding/cannot/reach".to_string();
let report = Pointer::parse(&invalid)
.diagnose(invalid.as_str())
.unwrap_err();
report.into_owned()
};

println!("{owned_report}");
// creating owned string to ensure its lifetime is local
// (could also coerce a static reference, but this is less brittle)
let invalid = "/foo/bar/invalid~3~encoding/cannot/reach".to_string();
let report = Pointer::parse(&invalid)
.diagnose(invalid.as_str())
.unwrap_err();

println!("{report}");
}
}
7 changes: 5 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,13 @@ pub use resolve::{Resolve, ResolveMut};
pub mod diagnostic;

mod pointer;
pub use pointer::{ParseError, Pointer, PointerBuf};
pub use pointer::{ParseError, ParseErrors, Pointer, PointerBuf, RichParseError};

mod token;
pub use token::{InvalidEncodingError, Token, Tokens};
pub use token::{EncodingError, InvalidEncoding, Token, Tokens};

#[allow(deprecated)]
pub use token::InvalidEncodingError;

pub mod index;

Expand Down
Loading
Loading