mirror of https://github.com/zkat/miette.git
Merge f346d78d21 into b466948965
This commit is contained in:
commit
f834b05a26
|
|
@ -68,6 +68,21 @@ jobs:
|
|||
- name: Check wasm target
|
||||
run: cargo check --target wasm32-unknown-unknown --features fancy-no-syscall
|
||||
|
||||
no-std:
|
||||
name: Check no-std build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: stable
|
||||
targets: wasm32-unknown-unknown
|
||||
- name: Check no-std core build
|
||||
run: cargo check --target wasm32-unknown-unknown --no-default-features
|
||||
- name: Check no-std with fancy-no-syscall
|
||||
run: cargo check --target wasm32-unknown-unknown --no-default-features --features fancy-no-syscall
|
||||
|
||||
miri:
|
||||
name: Miri
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -84,6 +99,20 @@ jobs:
|
|||
MIRIFLAGS: -Zmiri-disable-isolation -Zmiri-strict-provenance
|
||||
run: cargo miri test --all --verbose --features fancy
|
||||
|
||||
feature-check:
|
||||
name: Feature combinations check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install cargo-hack
|
||||
uses: taiki-e/install-action@cargo-hack
|
||||
- name: Check feature powerset
|
||||
run: cargo hack check --feature-powerset --no-dev-deps --skip default
|
||||
|
||||
minimal_versions:
|
||||
name: Minimal versions check
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ exclude = ["images/", "tests/", "miette-derive/"]
|
|||
miette-derive = { path = "miette-derive", version = "=7.6.0", optional = true }
|
||||
unicode-width = "0.2.0"
|
||||
cfg-if = "1.0.0"
|
||||
spin = { version = "0.9", default-features = false, features = ["once"] }
|
||||
|
||||
owo-colors = { version = "4.0.0", optional = true }
|
||||
textwrap = { version = "0.16.0", default-features = false, features = ["unicode-linebreak", "unicode-width"], optional = true }
|
||||
|
|
@ -31,21 +32,20 @@ syntect = { version = "5.1.0", optional = true }
|
|||
[dev-dependencies]
|
||||
thiserror = "2.0.11"
|
||||
semver = "1.0.21"
|
||||
|
||||
# Eyre devdeps
|
||||
futures = { version = "0.3", default-features = false }
|
||||
indenter = "0.3.3"
|
||||
rustversion = "1.0"
|
||||
trybuild = { version = "1.0.89", features = ["diff"] }
|
||||
syn = { version = "2.0.87", features = ["full"] }
|
||||
regex = "1.10"
|
||||
|
||||
serde = { version = "1.0.196", features = ["derive"] }
|
||||
serde_json = "1.0.113"
|
||||
strip-ansi-escapes = "0.2.0"
|
||||
|
||||
|
||||
[features]
|
||||
default = ["derive"]
|
||||
default = ["derive", "std"]
|
||||
std = []
|
||||
derive = ["dep:miette-derive"]
|
||||
no-format-args-capture = []
|
||||
fancy-base = [
|
||||
|
|
@ -57,6 +57,7 @@ fancy-no-syscall = [
|
|||
]
|
||||
fancy-no-backtrace = [
|
||||
"fancy-base",
|
||||
"std",
|
||||
"dep:terminal_size",
|
||||
"dep:supports-hyperlinks",
|
||||
"dep:supports-color",
|
||||
|
|
|
|||
17
README.md
17
README.md
|
|
@ -58,8 +58,8 @@ diagnostic error code: ruget::api::bad_json
|
|||
|
||||
### Features
|
||||
|
||||
- Generic [`Diagnostic`] protocol, compatible (and dependent on)
|
||||
[`std::error::Error`].
|
||||
- Generic [`Diagnostic`] protocol, compatible with `std::error::Error`.
|
||||
Works without the standard library: Just turn off the default `std` feature and you can use `miette` in places like embedded systems or web browsers that don't have the full standard library. You still need `alloc` for memory management.
|
||||
- Unique error codes on every [`Diagnostic`].
|
||||
- Custom links to get more details on error codes.
|
||||
- Super handy derive macro for defining diagnostic metadata.
|
||||
|
|
@ -93,6 +93,19 @@ If you want to use the fancy printer in all these screenshots:
|
|||
$ cargo add miette --features fancy
|
||||
```
|
||||
|
||||
For computers without the standard library (like microcontrollers or web browsers):
|
||||
|
||||
```sh
|
||||
$ cargo add miette --no-default-features --features derive
|
||||
```
|
||||
|
||||
Available features you can turn on or off:
|
||||
- `std` (on by default): Use the standard library
|
||||
- `derive`: Lets you automatically create error types
|
||||
- `fancy`: Shows pretty error messages with colors
|
||||
- `fancy-no-syscall`: Pretty errors without using system calls
|
||||
- `fancy-no-backtrace`: Pretty errors without showing the call stack
|
||||
|
||||
### Example
|
||||
|
||||
```rust
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
//! so the decoding source will be annotated with the decoding error,
|
||||
//! providing contextual information about the error.
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use miette::{IntoDiagnostic, SourceOffset};
|
||||
use serde_json::{self, json};
|
||||
|
||||
|
|
|
|||
|
|
@ -56,13 +56,13 @@ impl Code {
|
|||
let code = &code.as_ref()?.0;
|
||||
Some(match fields {
|
||||
syn::Fields::Named(_) => {
|
||||
quote! { Self::#ident { .. } => std::option::Option::Some(std::boxed::Box::new(#code)), }
|
||||
quote! { Self::#ident { .. } => core::option::Option::Some(miette::__alloc::Box::new(#code)), }
|
||||
}
|
||||
syn::Fields::Unnamed(_) => {
|
||||
quote! { Self::#ident(..) => std::option::Option::Some(std::boxed::Box::new(#code)), }
|
||||
quote! { Self::#ident(..) => core::option::Option::Some(miette::__alloc::Box::new(#code)), }
|
||||
}
|
||||
syn::Fields::Unit => {
|
||||
quote! { Self::#ident => std::option::Option::Some(std::boxed::Box::new(#code)), }
|
||||
quote! { Self::#ident => core::option::Option::Some(miette::__alloc::Box::new(#code)), }
|
||||
}
|
||||
})
|
||||
},
|
||||
|
|
@ -72,8 +72,8 @@ impl Code {
|
|||
pub(crate) fn gen_struct(&self) -> Option<TokenStream> {
|
||||
let code = &self.0;
|
||||
Some(quote! {
|
||||
fn code(&self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>> {
|
||||
std::option::Option::Some(std::boxed::Box::new(#code))
|
||||
fn code(&self) -> core::option::Option<miette::__alloc::Box<dyn core::fmt::Display + '_>> {
|
||||
core::option::Option::Some(miette::__alloc::Box::new(#code))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ impl DiagnosticSource {
|
|||
};
|
||||
quote! {
|
||||
Self::#ident #display_pat => {
|
||||
std::option::Option::Some(std::borrow::Borrow::borrow(#rel))
|
||||
core::option::Option::Some(miette::__alloc::borrow::Borrow::borrow(#rel))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -70,8 +70,8 @@ impl DiagnosticSource {
|
|||
pub(crate) fn gen_struct(&self) -> Option<TokenStream> {
|
||||
let rel = &self.0;
|
||||
Some(quote! {
|
||||
fn diagnostic_source<'a>(&'a self) -> std::option::Option<&'a dyn miette::Diagnostic> {
|
||||
std::option::Option::Some(std::borrow::Borrow::borrow(&self.#rel))
|
||||
fn diagnostic_source<'a>(&'a self) -> core::option::Option<&'a dyn miette::Diagnostic> {
|
||||
core::option::Option::Some(miette::__alloc::borrow::Borrow::borrow(&self.#rel))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,34 +58,34 @@ impl WhichFn {
|
|||
pub fn signature(&self) -> TokenStream {
|
||||
match self {
|
||||
Self::Code => quote! {
|
||||
fn code(& self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>>
|
||||
fn code(& self) -> Option<miette::__alloc::Box<dyn core::fmt::Display + '_>>
|
||||
},
|
||||
Self::Help => quote! {
|
||||
fn help(& self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>>
|
||||
fn help(& self) -> Option<miette::__alloc::Box<dyn core::fmt::Display + '_>>
|
||||
},
|
||||
Self::Url => quote! {
|
||||
fn url(& self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>>
|
||||
fn url(& self) -> Option<miette::__alloc::Box<dyn core::fmt::Display + '_>>
|
||||
},
|
||||
Self::Severity => quote! {
|
||||
fn severity(&self) -> std::option::Option<miette::Severity>
|
||||
fn severity(&self) -> Option<miette::Severity>
|
||||
},
|
||||
Self::Related => quote! {
|
||||
fn related(&self) -> std::option::Option<std::boxed::Box<dyn std::iter::Iterator<Item = &dyn miette::Diagnostic> + '_>>
|
||||
fn related(&self) -> Option<miette::__alloc::Box<dyn Iterator<Item = &dyn miette::Diagnostic> + '_>>
|
||||
},
|
||||
Self::Labels => quote! {
|
||||
fn labels(&self) -> std::option::Option<std::boxed::Box<dyn std::iter::Iterator<Item = miette::LabeledSpan> + '_>>
|
||||
fn labels(&self) -> Option<miette::__alloc::Box<dyn Iterator<Item = miette::LabeledSpan> + '_>>
|
||||
},
|
||||
Self::SourceCode => quote! {
|
||||
fn source_code(&self) -> std::option::Option<&dyn miette::SourceCode>
|
||||
fn source_code(&self) -> Option<&dyn miette::SourceCode>
|
||||
},
|
||||
Self::DiagnosticSource => quote! {
|
||||
fn diagnostic_source(&self) -> std::option::Option<&dyn miette::Diagnostic>
|
||||
fn diagnostic_source(&self) -> Option<&dyn miette::Diagnostic>
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn catchall_arm(&self) -> TokenStream {
|
||||
quote! { _ => std::option::Option::None }
|
||||
quote! { _ => Option::None }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ impl Help {
|
|||
Help::Display(display) => {
|
||||
let (fmt, args) = display.expand_shorthand_cloned(&display_members);
|
||||
Some(quote! {
|
||||
Self::#ident #display_pat => std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args))),
|
||||
Self::#ident #display_pat => Option::Some(miette::__alloc::Box::new(format!(#fmt #args))),
|
||||
})
|
||||
}
|
||||
Help::Field(member, ty) => {
|
||||
|
|
@ -108,7 +108,7 @@ impl Help {
|
|||
Some(quote! {
|
||||
Self::#ident #display_pat => {
|
||||
use miette::macro_helpers::ToOption;
|
||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(&#help).as_ref().map(|#var| -> std::boxed::Box<dyn std::fmt::Display + '_> { std::boxed::Box::new(format!("{}", #var)) })
|
||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(&#help).as_ref().map(|#var| -> miette::__alloc::Box<dyn core::fmt::Display + '_> { miette::__alloc::Box::new(format!("{}", #var)) })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -123,21 +123,21 @@ impl Help {
|
|||
Help::Display(display) => {
|
||||
let (fmt, args) = display.expand_shorthand_cloned(&display_members);
|
||||
Some(quote! {
|
||||
fn help(&self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>> {
|
||||
fn help(&self) -> Option<miette::__alloc::Box<dyn core::fmt::Display + '_>> {
|
||||
#[allow(unused_variables, deprecated)]
|
||||
let Self #display_pat = self;
|
||||
std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args)))
|
||||
Option::Some(miette::__alloc::Box::new(format!(#fmt #args)))
|
||||
}
|
||||
})
|
||||
}
|
||||
Help::Field(member, ty) => {
|
||||
let var = quote! { __miette_internal_var };
|
||||
Some(quote! {
|
||||
fn help(&self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>> {
|
||||
fn help(&self) -> Option<miette::__alloc::Box<dyn core::fmt::Display + '_>> {
|
||||
#[allow(unused_variables, deprecated)]
|
||||
let Self #display_pat = self;
|
||||
use miette::macro_helpers::ToOption;
|
||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(&self.#member).as_ref().map(|#var| -> std::boxed::Box<dyn std::fmt::Display + '_> { std::boxed::Box::new(format!("{}", #var)) })
|
||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(&self.#member).as_ref().map(|#var| -> miette::__alloc::Box<dyn core::fmt::Display + '_> { miette::__alloc::Box::new(format!("{}", #var)) })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,9 +175,9 @@ impl Labels {
|
|||
let var = quote! { __miette_internal_var };
|
||||
let display = if let Some(display) = label {
|
||||
let (fmt, args) = display.expand_shorthand_cloned(&display_members);
|
||||
quote! { std::option::Option::Some(format!(#fmt #args)) }
|
||||
quote! { Option::Some(format!(#fmt #args)) }
|
||||
} else {
|
||||
quote! { std::option::Option::None }
|
||||
quote! { Option::None }
|
||||
};
|
||||
let ctor = if *lbl_ty == LabelType::Primary {
|
||||
quote! { miette::LabeledSpan::new_primary_with_span }
|
||||
|
|
@ -205,9 +205,9 @@ impl Labels {
|
|||
}
|
||||
let display = if let Some(display) = label {
|
||||
let (fmt, args) = display.expand_shorthand_cloned(&display_members);
|
||||
quote! { std::option::Option::Some(format!(#fmt #args)) }
|
||||
quote! { Option::Some(format!(#fmt #args)) }
|
||||
} else {
|
||||
quote! { std::option::Option::None }
|
||||
quote! { Option::None }
|
||||
};
|
||||
Some(quote! {
|
||||
.chain({
|
||||
|
|
@ -226,7 +226,7 @@ impl Labels {
|
|||
|
||||
Some(quote! {
|
||||
#[allow(unused_variables)]
|
||||
fn labels(&self) -> std::option::Option<std::boxed::Box<dyn std::iter::Iterator<Item = miette::LabeledSpan> + '_>> {
|
||||
fn labels(&self) -> Option<miette::__alloc::Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
|
||||
use miette::macro_helpers::ToOption;
|
||||
let Self #display_pat = self;
|
||||
|
||||
|
|
@ -236,7 +236,7 @@ impl Labels {
|
|||
.into_iter()
|
||||
#(#collections_chain)*;
|
||||
|
||||
std::option::Option::Some(Box::new(labels_iter.filter(Option::is_some).map(Option::unwrap)))
|
||||
Option::Some(miette::__alloc::Box::new(labels_iter.filter(Option::is_some).map(Option::unwrap)))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -322,7 +322,7 @@ impl Labels {
|
|||
]
|
||||
.into_iter()
|
||||
#(#collections_chain)*;
|
||||
std::option::Option::Some(std::boxed::Box::new(labels_iter.filter(Option::is_some).map(Option::unwrap)))
|
||||
Option::Some(miette::__alloc::Box::new(labels_iter.filter(Option::is_some).map(Option::unwrap)))
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ impl Related {
|
|||
};
|
||||
quote! {
|
||||
Self::#ident #display_pat => {
|
||||
std::option::Option::Some(std::boxed::Box::new(
|
||||
Option::Some(miette::__alloc::Box::new(
|
||||
#rel.iter().map(|x| -> &(dyn miette::Diagnostic) { &*x })
|
||||
))
|
||||
}
|
||||
|
|
@ -68,9 +68,9 @@ impl Related {
|
|||
pub(crate) fn gen_struct(&self) -> Option<TokenStream> {
|
||||
let rel = &self.0;
|
||||
Some(quote! {
|
||||
fn related<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::iter::Iterator<Item = &'a dyn miette::Diagnostic> + 'a>> {
|
||||
use ::core::borrow::Borrow;
|
||||
std::option::Option::Some(std::boxed::Box::new(
|
||||
fn related<'a>(&'a self) -> Option<miette::__alloc::Box<dyn Iterator<Item = &'a dyn miette::Diagnostic> + 'a>> {
|
||||
use miette::__alloc::borrow::Borrow;
|
||||
Option::Some(miette::__alloc::Box::new(
|
||||
self.#rel.iter().map(|x| -> &(dyn miette::Diagnostic) { &*x.borrow() })
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,9 +71,7 @@ impl Severity {
|
|||
syn::Fields::Unnamed(_) => quote! { (..) },
|
||||
syn::Fields::Unit => quote! {},
|
||||
};
|
||||
Some(
|
||||
quote! { Self::#ident #fields => std::option::Option::Some(miette::Severity::#severity), },
|
||||
)
|
||||
Some(quote! { Self::#ident #fields => Option::Some(miette::Severity::#severity), })
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ impl SourceCode {
|
|||
|
||||
Some(quote! {
|
||||
#[allow(unused_variables)]
|
||||
fn source_code(&self) -> std::option::Option<&dyn miette::SourceCode> {
|
||||
fn source_code(&self) -> Option<&dyn miette::SourceCode> {
|
||||
let Self #display_pat = self;
|
||||
#ret
|
||||
}
|
||||
|
|
@ -101,7 +101,7 @@ impl SourceCode {
|
|||
}
|
||||
} else {
|
||||
quote! {
|
||||
std::option::Option::Some(#field)
|
||||
Option::Some(#field)
|
||||
}
|
||||
};
|
||||
match &fields {
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ impl Url {
|
|||
}
|
||||
};
|
||||
Some(quote! {
|
||||
Self::#ident #pat => std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args))),
|
||||
Self::#ident #pat => Option::Some(miette::__alloc::Box::new(format!(#fmt #args))),
|
||||
})
|
||||
},
|
||||
)
|
||||
|
|
@ -129,10 +129,10 @@ impl Url {
|
|||
}
|
||||
};
|
||||
Some(quote! {
|
||||
fn url(&self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>> {
|
||||
fn url(&self) -> Option<miette::__alloc::Box<dyn core::fmt::Display + '_>> {
|
||||
#[allow(unused_variables, deprecated)]
|
||||
let Self #pat = self;
|
||||
std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args)))
|
||||
Option::Some(miette::__alloc::Box::new(format!(#fmt #args)))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ Iterate over error `.source()` chains.
|
|||
|
||||
NOTE: This module is taken wholesale from <https://crates.io/crates/eyre>.
|
||||
*/
|
||||
use std::error::Error as StdError;
|
||||
use std::vec;
|
||||
extern crate alloc;
|
||||
|
||||
use crate::StdError;
|
||||
use alloc::vec::{self, Vec};
|
||||
|
||||
use ChainState::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ impl<'a> DiagnosticChain<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_stderror(head: &'a (dyn std::error::Error + 'static)) -> Self {
|
||||
pub(crate) fn from_stderror(head: &'a (dyn crate::StdError + 'static)) -> Self {
|
||||
DiagnosticChain {
|
||||
state: Some(ErrorKind::StdError(head)),
|
||||
}
|
||||
|
|
@ -59,7 +59,7 @@ impl ExactSizeIterator for DiagnosticChain<'_> {
|
|||
#[derive(Clone)]
|
||||
pub(crate) enum ErrorKind<'a> {
|
||||
Diagnostic(&'a dyn Diagnostic),
|
||||
StdError(&'a (dyn std::error::Error + 'static)),
|
||||
StdError(&'a (dyn crate::StdError + 'static)),
|
||||
}
|
||||
|
||||
impl<'a> ErrorKind<'a> {
|
||||
|
|
@ -74,8 +74,8 @@ impl<'a> ErrorKind<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ErrorKind<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
impl core::fmt::Debug for ErrorKind<'_> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
ErrorKind::Diagnostic(d) => d.fmt(f),
|
||||
ErrorKind::StdError(e) => e.fmt(f),
|
||||
|
|
@ -83,8 +83,8 @@ impl std::fmt::Debug for ErrorKind<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ErrorKind<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
impl core::fmt::Display for ErrorKind<'_> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
ErrorKind::Diagnostic(d) => d.fmt(f),
|
||||
ErrorKind::StdError(e) => e.fmt(f),
|
||||
|
|
|
|||
|
|
@ -1,11 +1,16 @@
|
|||
/*!
|
||||
Default trait implementations for [`Diagnostic`].
|
||||
*/
|
||||
extern crate alloc;
|
||||
|
||||
use std::{convert::Infallible, fmt::Display};
|
||||
use alloc::boxed::Box;
|
||||
use core::{convert::Infallible, fmt::Display};
|
||||
|
||||
use crate::{Diagnostic, LabeledSpan, Severity, SourceCode};
|
||||
|
||||
// Note: Infallible implements core::error::Error since Rust 1.81,
|
||||
// so we don't need to provide our own StdError impl.
|
||||
|
||||
impl Diagnostic for Infallible {
|
||||
fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||
match *self {}
|
||||
|
|
|
|||
47
src/error.rs
47
src/error.rs
|
|
@ -1,8 +1,10 @@
|
|||
use std::{
|
||||
error::Error,
|
||||
fmt::{self, Display},
|
||||
io,
|
||||
};
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use core::error::Error;
|
||||
use core::fmt::{self, Display};
|
||||
#[cfg(feature = "std")]
|
||||
use std::io;
|
||||
|
||||
use crate::Diagnostic;
|
||||
|
||||
|
|
@ -11,8 +13,9 @@ Error enum for miette. Used by certain operations in the protocol.
|
|||
*/
|
||||
#[derive(Debug)]
|
||||
pub enum MietteError {
|
||||
/// Wrapper around [`std::io::Error`]. This is returned when something went
|
||||
/// Wrapper around [`io::Error`]. This is returned when something went
|
||||
/// wrong while reading a [`SourceCode`](crate::SourceCode).
|
||||
#[cfg(feature = "std")]
|
||||
IoError(io::Error),
|
||||
|
||||
/// Returned when a [`SourceSpan`](crate::SourceSpan) extends beyond the
|
||||
|
|
@ -23,6 +26,7 @@ pub enum MietteError {
|
|||
impl Display for MietteError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
#[cfg(feature = "std")]
|
||||
MietteError::IoError(error) => write!(f, "{error}"),
|
||||
MietteError::OutOfBounds => {
|
||||
write!(f, "The given offset is outside the bounds of its Source")
|
||||
|
|
@ -34,12 +38,14 @@ impl Display for MietteError {
|
|||
impl Error for MietteError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
match self {
|
||||
#[cfg(feature = "std")]
|
||||
MietteError::IoError(error) => error.source(),
|
||||
MietteError::OutOfBounds => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<io::Error> for MietteError {
|
||||
fn from(value: io::Error) -> Self {
|
||||
Self::IoError(value)
|
||||
|
|
@ -49,6 +55,7 @@ impl From<io::Error> for MietteError {
|
|||
impl Diagnostic for MietteError {
|
||||
fn code<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
|
||||
match self {
|
||||
#[cfg(feature = "std")]
|
||||
MietteError::IoError(_) => Some(Box::new("miette::io_error")),
|
||||
MietteError::OutOfBounds => Some(Box::new("miette::span_out_of_bounds")),
|
||||
}
|
||||
|
|
@ -56,6 +63,7 @@ impl Diagnostic for MietteError {
|
|||
|
||||
fn help<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
|
||||
match self {
|
||||
#[cfg(feature = "std")]
|
||||
MietteError::IoError(_) => None,
|
||||
MietteError::OutOfBounds => Some(Box::new(
|
||||
"Double-check your spans. Do you have an off-by-one error?",
|
||||
|
|
@ -66,24 +74,32 @@ impl Diagnostic for MietteError {
|
|||
fn url<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
|
||||
let crate_version = env!("CARGO_PKG_VERSION");
|
||||
let variant = match self {
|
||||
#[cfg(feature = "std")]
|
||||
MietteError::IoError(_) => "#variant.IoError",
|
||||
MietteError::OutOfBounds => "#variant.OutOfBounds",
|
||||
};
|
||||
Some(Box::new(format!(
|
||||
Some(Box::new(alloc::format!(
|
||||
"https://docs.rs/miette/{}/miette/enum.MietteError.html{}",
|
||||
crate_version, variant,
|
||||
crate_version,
|
||||
variant,
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use std::{error::Error, io::ErrorKind};
|
||||
#[cfg(not(feature = "std"))]
|
||||
use crate::StdError as Error;
|
||||
use alloc::string::ToString;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg(feature = "std")]
|
||||
pub(crate) struct TestError(pub(crate) io::Error);
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct TestError(pub(crate) &'static str);
|
||||
|
||||
impl Display for TestError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
|
@ -91,17 +107,26 @@ pub(crate) mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Error for TestError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
Some(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
impl Error for TestError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn io_error() {
|
||||
let inner_error = io::Error::new(ErrorKind::Other, "halt and catch fire");
|
||||
let inner_error = io::Error::other("halt and catch fire");
|
||||
let outer_error = TestError(inner_error);
|
||||
let io_error = io::Error::new(ErrorKind::Other, outer_error);
|
||||
let io_error = io::Error::other(outer_error);
|
||||
|
||||
let miette_error = MietteError::from(io_error);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
extern crate alloc;
|
||||
|
||||
use super::error::{ContextError, ErrorImpl};
|
||||
use super::{Report, WrapErr};
|
||||
use core::convert::Infallible;
|
||||
use core::fmt::{self, Debug, Display, Write};
|
||||
|
||||
use std::error::Error as StdError;
|
||||
use crate::StdError;
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use crate::{Diagnostic, LabeledSpan};
|
||||
|
||||
|
|
@ -10,7 +14,7 @@ mod ext {
|
|||
use super::*;
|
||||
|
||||
pub trait Diag {
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
fn ext_report<D>(self, msg: D) -> Report
|
||||
where
|
||||
D: Display + Send + Sync + 'static;
|
||||
|
|
@ -20,6 +24,7 @@ mod ext {
|
|||
where
|
||||
E: Diagnostic + Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn ext_report<D>(self, msg: D) -> Report
|
||||
where
|
||||
D: Display + Send + Sync + 'static,
|
||||
|
|
@ -29,6 +34,7 @@ mod ext {
|
|||
}
|
||||
|
||||
impl Diag for Report {
|
||||
#[track_caller]
|
||||
fn ext_report<D>(self, msg: D) -> Report
|
||||
where
|
||||
D: Display + Send + Sync + 'static,
|
||||
|
|
@ -38,7 +44,8 @@ mod ext {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> WrapErr<T, std::convert::Infallible> for Option<T> {
|
||||
impl<T> WrapErr<T, Infallible> for Option<T> {
|
||||
#[track_caller]
|
||||
fn wrap_err<D>(self, msg: D) -> Result<T, Report>
|
||||
where
|
||||
D: Display + Send + Sync + 'static,
|
||||
|
|
@ -49,6 +56,7 @@ impl<T> WrapErr<T, std::convert::Infallible> for Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn wrap_err_with<D, F>(self, msg: F) -> Result<T, Report>
|
||||
where
|
||||
D: Display + Send + Sync + 'static,
|
||||
|
|
@ -60,6 +68,7 @@ impl<T> WrapErr<T, std::convert::Infallible> for Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn context<D>(self, msg: D) -> Result<T, Report>
|
||||
where
|
||||
D: Display + Send + Sync + 'static,
|
||||
|
|
@ -67,6 +76,7 @@ impl<T> WrapErr<T, std::convert::Infallible> for Option<T> {
|
|||
self.wrap_err(msg)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn with_context<D, F>(self, msg: F) -> Result<T, Report>
|
||||
where
|
||||
D: Display + Send + Sync + 'static,
|
||||
|
|
@ -80,6 +90,7 @@ impl<T, E> WrapErr<T, E> for Result<T, E>
|
|||
where
|
||||
E: ext::Diag + Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn wrap_err<D>(self, msg: D) -> Result<T, Report>
|
||||
where
|
||||
D: Display + Send + Sync + 'static,
|
||||
|
|
@ -90,6 +101,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn wrap_err_with<D, F>(self, msg: F) -> Result<T, Report>
|
||||
where
|
||||
D: Display + Send + Sync + 'static,
|
||||
|
|
@ -101,6 +113,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn context<D>(self, msg: D) -> Result<T, Report>
|
||||
where
|
||||
D: Display + Send + Sync + 'static,
|
||||
|
|
@ -108,6 +121,7 @@ where
|
|||
self.wrap_err(msg)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn with_context<D, F>(self, msg: F) -> Result<T, Report>
|
||||
where
|
||||
D: Display + Send + Sync + 'static,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
extern crate alloc;
|
||||
|
||||
use crate::StdError;
|
||||
use alloc::boxed::Box;
|
||||
use core::any::TypeId;
|
||||
use core::fmt::{self, Debug, Display};
|
||||
use core::mem::ManuallyDrop;
|
||||
use core::ptr::{self, NonNull};
|
||||
use std::error::Error as StdError;
|
||||
|
||||
use super::ptr::{Mut, Own, Ref};
|
||||
use super::Report;
|
||||
|
|
@ -20,7 +23,7 @@ impl Report {
|
|||
///
|
||||
/// If the error type does not provide a backtrace, a backtrace will be
|
||||
/// created here to ensure that a backtrace exists.
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
#[cold]
|
||||
pub fn new<E>(error: E) -> Self
|
||||
where
|
||||
|
|
@ -66,7 +69,7 @@ impl Report {
|
|||
/// .await
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
#[cold]
|
||||
pub fn msg<M>(message: M) -> Self
|
||||
where
|
||||
|
|
@ -82,12 +85,11 @@ impl Report {
|
|||
///
|
||||
/// Boxed `Diagnostic`s don't implement `Diagnostic` themselves due to trait coherence issues.
|
||||
/// This method allows you to create a `Report` from a boxed `Diagnostic`.
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
pub fn new_boxed(error: Box<dyn Diagnostic + Send + Sync + 'static>) -> Self {
|
||||
Report::from_boxed(error)
|
||||
}
|
||||
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[cold]
|
||||
pub(crate) fn from_std<E>(error: E) -> Self
|
||||
where
|
||||
|
|
@ -109,7 +111,7 @@ impl Report {
|
|||
unsafe { Report::construct(error, vtable, handler) }
|
||||
}
|
||||
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
#[cold]
|
||||
pub(crate) fn from_adhoc<M>(message: M) -> Self
|
||||
where
|
||||
|
|
@ -134,7 +136,7 @@ impl Report {
|
|||
unsafe { Report::construct(error, vtable, handler) }
|
||||
}
|
||||
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
#[cold]
|
||||
pub(crate) fn from_msg<D, E>(msg: D, error: E) -> Self
|
||||
where
|
||||
|
|
@ -154,12 +156,12 @@ impl Report {
|
|||
};
|
||||
|
||||
// Safety: passing vtable that operates on the right type.
|
||||
let handler = Some(super::capture_handler(&error));
|
||||
let handler = Some(super::capture_handler_with_location(&error));
|
||||
|
||||
unsafe { Report::construct(error, vtable, handler) }
|
||||
}
|
||||
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
#[cold]
|
||||
pub(crate) fn from_boxed(error: Box<dyn Diagnostic + Send + Sync>) -> Self {
|
||||
use super::wrapper::BoxedError;
|
||||
|
|
@ -429,7 +431,7 @@ impl Report {
|
|||
/// Construct a [`Report`] directly from an error-like type
|
||||
pub fn from_err<E>(err: E) -> Self
|
||||
where
|
||||
E: std::error::Error + Send + Sync + 'static,
|
||||
E: StdError + Send + Sync + 'static,
|
||||
{
|
||||
super::DiagnosticError(Box::new(err)).into()
|
||||
}
|
||||
|
|
@ -439,7 +441,6 @@ impl<E> From<E> for Report
|
|||
where
|
||||
E: Diagnostic + Send + Sync + 'static,
|
||||
{
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[cold]
|
||||
fn from(error: E) -> Self {
|
||||
Report::from_std(error)
|
||||
|
|
@ -816,7 +817,7 @@ impl AsRef<dyn StdError> for Report {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::borrow::Borrow<dyn Diagnostic> for Report {
|
||||
impl core::borrow::Borrow<dyn Diagnostic> for Report {
|
||||
fn borrow(&self) -> &(dyn Diagnostic + 'static) {
|
||||
self.as_ref()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
use std::{error::Error, fmt::Display};
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use core::error::Error;
|
||||
|
||||
use crate::{Diagnostic, Report};
|
||||
|
||||
/// Convenience [`Diagnostic`] that can be used as an "anonymous" wrapper for
|
||||
/// Errors. This is intended to be paired with [`IntoDiagnostic`].
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct DiagnosticError(pub(crate) Box<dyn std::error::Error + Send + Sync + 'static>);
|
||||
pub(crate) struct DiagnosticError(pub(crate) Box<dyn Error + Send + Sync + 'static>);
|
||||
|
||||
impl Display for DiagnosticError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
impl core::fmt::Display for DiagnosticError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
let msg = &self.0;
|
||||
write!(f, "{msg}")
|
||||
}
|
||||
|
|
@ -35,10 +38,12 @@ inaccessible. If you have a type implementing [`Diagnostic`] consider simply ret
|
|||
pub trait IntoDiagnostic<T, E> {
|
||||
/// Converts [`Result`] types that return regular [`std::error::Error`]s
|
||||
/// into a [`Result`] that returns a [`Diagnostic`].
|
||||
#[track_caller]
|
||||
fn into_diagnostic(self) -> Result<T, Report>;
|
||||
}
|
||||
|
||||
impl<T, E: std::error::Error + Send + Sync + 'static> IntoDiagnostic<T, E> for Result<T, E> {
|
||||
impl<T, E: Error + Send + Sync + 'static> IntoDiagnostic<T, E> for Result<T, E> {
|
||||
#[track_caller]
|
||||
fn into_diagnostic(self) -> Result<T, Report> {
|
||||
self.map_err(|e| DiagnosticError(Box::new(e)).into())
|
||||
}
|
||||
|
|
@ -46,15 +51,21 @@ impl<T, E: std::error::Error + Send + Sync + 'static> IntoDiagnostic<T, E> for R
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io::{self, ErrorKind};
|
||||
extern crate alloc;
|
||||
|
||||
use super::*;
|
||||
use alloc::string::ToString;
|
||||
|
||||
use super::IntoDiagnostic;
|
||||
#[cfg(feature = "std")]
|
||||
use std::io;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::error::tests::TestError;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn diagnostic_error() {
|
||||
let inner_error = io::Error::new(ErrorKind::Other, "halt and catch fire");
|
||||
let inner_error = io::Error::other("halt and catch fire");
|
||||
let outer_error: Result<(), _> = Err(TestError(inner_error));
|
||||
|
||||
let diagnostic_error = outer_error.into_diagnostic().unwrap_err();
|
||||
|
|
|
|||
|
|
@ -45,9 +45,12 @@
|
|||
// let error = $msg;
|
||||
// (&error).miette_kind().new(error)
|
||||
|
||||
use super::Report;
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use core::fmt::{Debug, Display};
|
||||
|
||||
use super::Report;
|
||||
use crate::Diagnostic;
|
||||
|
||||
pub struct Adhoc;
|
||||
|
|
@ -62,7 +65,7 @@ pub trait AdhocKind: Sized {
|
|||
impl<T> AdhocKind for &T where T: ?Sized + Display + Debug + Send + Sync + 'static {}
|
||||
|
||||
impl Adhoc {
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
#[cold]
|
||||
pub fn new<M>(self, message: M) -> Report
|
||||
where
|
||||
|
|
@ -84,7 +87,7 @@ pub trait TraitKind: Sized {
|
|||
impl<E> TraitKind for E where E: Into<Report> {}
|
||||
|
||||
impl Trait {
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
#[cold]
|
||||
pub fn new<E>(self, error: E) -> Report
|
||||
where
|
||||
|
|
@ -106,7 +109,7 @@ pub trait BoxedKind: Sized {
|
|||
impl BoxedKind for Box<dyn Diagnostic + Send + Sync> {}
|
||||
|
||||
impl Boxed {
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
#[cold]
|
||||
pub fn new(self, error: Box<dyn Diagnostic + Send + Sync>) -> Report {
|
||||
Report::from_boxed(error)
|
||||
|
|
|
|||
|
|
@ -4,9 +4,13 @@
|
|||
clippy::new_ret_no_self,
|
||||
clippy::wrong_self_convention
|
||||
)]
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use core::fmt::Display;
|
||||
|
||||
use std::error::Error as StdError;
|
||||
use core::error::Error as StdError;
|
||||
#[cfg(feature = "std")]
|
||||
use std::sync::OnceLock;
|
||||
|
||||
#[allow(unreachable_pub)]
|
||||
|
|
@ -61,8 +65,16 @@ unsafe impl Send for Report {}
|
|||
pub type ErrorHook =
|
||||
Box<dyn Fn(&(dyn Diagnostic + 'static)) -> Box<dyn ReportHandler> + Sync + Send + 'static>;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
static HOOK: OnceLock<ErrorHook> = OnceLock::new();
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
static HOOK: spin::Once<ErrorHook> = spin::Once::new();
|
||||
|
||||
fn default_hook() -> ErrorHook {
|
||||
Box::new(get_default_printer)
|
||||
}
|
||||
|
||||
/// Error indicating that [`set_hook()`] was unable to install the provided
|
||||
/// [`ErrorHook`].
|
||||
#[derive(Debug)]
|
||||
|
|
@ -77,28 +89,51 @@ impl core::fmt::Display for InstallError {
|
|||
impl StdError for InstallError {}
|
||||
impl Diagnostic for InstallError {}
|
||||
|
||||
/**
|
||||
Set the error hook.
|
||||
*/
|
||||
/// Set the error hook.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn set_hook(hook: ErrorHook) -> Result<(), InstallError> {
|
||||
HOOK.set(hook).map_err(|_| InstallError)
|
||||
}
|
||||
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[cfg_attr(not(track_caller), allow(unused_mut))]
|
||||
fn capture_handler(error: &(dyn Diagnostic + 'static)) -> Box<dyn ReportHandler> {
|
||||
let hook = HOOK.get_or_init(|| Box::new(get_default_printer)).as_ref();
|
||||
/// Set the error hook.
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub fn set_hook(hook: ErrorHook) -> Result<(), InstallError> {
|
||||
HOOK.call_once(|| hook);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(track_caller)]
|
||||
{
|
||||
let mut handler = hook(error);
|
||||
handler.track_caller(std::panic::Location::caller());
|
||||
handler
|
||||
}
|
||||
#[cfg(not(track_caller))]
|
||||
{
|
||||
#[cfg(feature = "std")]
|
||||
pub(crate) fn capture_handler(error: &(dyn Diagnostic + 'static)) -> Box<dyn ReportHandler> {
|
||||
let hook = HOOK.get_or_init(default_hook);
|
||||
hook(error)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub(crate) fn capture_handler(error: &(dyn Diagnostic + 'static)) -> Box<dyn ReportHandler> {
|
||||
let hook = HOOK.call_once(default_hook);
|
||||
hook(error)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[cfg(feature = "std")]
|
||||
pub(crate) fn capture_handler_with_location(
|
||||
error: &(dyn Diagnostic + 'static),
|
||||
) -> Box<dyn ReportHandler> {
|
||||
let hook = HOOK.get_or_init(default_hook);
|
||||
let mut handler = hook(error);
|
||||
handler.track_caller(core::panic::Location::caller());
|
||||
handler
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub(crate) fn capture_handler_with_location(
|
||||
error: &(dyn Diagnostic + 'static),
|
||||
) -> Box<dyn ReportHandler> {
|
||||
let hook = HOOK.call_once(default_hook);
|
||||
let mut handler = hook(error);
|
||||
handler.track_caller(core::panic::Location::caller());
|
||||
handler
|
||||
}
|
||||
|
||||
fn get_default_printer(_err: &(dyn Diagnostic + 'static)) -> Box<dyn ReportHandler + 'static> {
|
||||
|
|
@ -193,7 +228,7 @@ pub trait ReportHandler: core::any::Any + Send + Sync {
|
|||
|
||||
/// Store the location of the caller who constructed this error report
|
||||
#[allow(unused_variables)]
|
||||
fn track_caller(&mut self, location: &'static std::panic::Location<'static>) {}
|
||||
fn track_caller(&mut self, location: &'static core::panic::Location<'static>) {}
|
||||
}
|
||||
|
||||
/// type alias for `Result<T, Report>`
|
||||
|
|
@ -428,27 +463,27 @@ pub type Result<T, E = Report> = core::result::Result<T, E>;
|
|||
/// ```
|
||||
pub trait WrapErr<T, E>: context::private::Sealed {
|
||||
/// Wrap the error value with a new adhoc error
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
fn wrap_err<D>(self, msg: D) -> Result<T, Report>
|
||||
where
|
||||
D: Display + Send + Sync + 'static;
|
||||
|
||||
/// Wrap the error value with a new adhoc error that is evaluated lazily
|
||||
/// only once an error does occur.
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
fn wrap_err_with<D, F>(self, f: F) -> Result<T, Report>
|
||||
where
|
||||
D: Display + Send + Sync + 'static,
|
||||
F: FnOnce() -> D;
|
||||
|
||||
/// Compatibility re-export of `wrap_err()` for interop with `anyhow`
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
fn context<D>(self, msg: D) -> Result<T, Report>
|
||||
where
|
||||
D: Display + Send + Sync + 'static;
|
||||
|
||||
/// Compatibility re-export of `wrap_err_with()` for interop with `anyhow`
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
fn with_context<D, F>(self, f: F) -> Result<T, Report>
|
||||
where
|
||||
D: Display + Send + Sync + 'static,
|
||||
|
|
@ -470,7 +505,7 @@ pub mod private {
|
|||
pub use super::super::kind::BoxedKind;
|
||||
}
|
||||
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
#[track_caller]
|
||||
#[cold]
|
||||
pub fn new_adhoc<M>(message: M) -> Report
|
||||
where
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
use std::{marker::PhantomData, ptr::NonNull};
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
#[repr(transparent)]
|
||||
/// A raw pointer that owns its pointee
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
extern crate alloc;
|
||||
|
||||
use core::fmt::{self, Debug, Display};
|
||||
|
||||
use std::error::Error as StdError;
|
||||
use crate::StdError;
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use crate::{Diagnostic, LabeledSpan, Report, SourceCode};
|
||||
|
||||
|
|
@ -107,16 +110,6 @@ impl StdError for BoxedError {
|
|||
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||
self.0.source()
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
#[allow(deprecated)]
|
||||
self.0.description()
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&dyn StdError> {
|
||||
#[allow(deprecated)]
|
||||
self.0.cause()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WithSourceCode<E, C> {
|
||||
|
|
@ -216,8 +209,16 @@ impl<C> StdError for WithSourceCode<Report, C> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, feature = "std"))]
|
||||
mod tests {
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
#[cfg(feature = "fancy")]
|
||||
use alloc::format;
|
||||
use alloc::string::{String, ToString};
|
||||
#[cfg(feature = "fancy")]
|
||||
use alloc::{vec, vec::Vec};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{Diagnostic, LabeledSpan, Report, SourceCode, SourceSpan};
|
||||
|
|
@ -231,7 +232,7 @@ mod tests {
|
|||
|
||||
impl Diagnostic for Inner {
|
||||
fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> {
|
||||
Some(Box::new(std::iter::once(LabeledSpan::underline(self.at))))
|
||||
Some(Box::new(core::iter::once(LabeledSpan::underline(self.at))))
|
||||
}
|
||||
|
||||
fn source_code(&self) -> Option<&dyn SourceCode> {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
extern crate alloc;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
|
||||
use crate::highlighters::Highlighter;
|
||||
use crate::highlighters::MietteHighlighter;
|
||||
use crate::protocol::Diagnostic;
|
||||
|
|
@ -8,7 +12,7 @@ use crate::ReportHandler;
|
|||
use crate::ThemeCharacters;
|
||||
use crate::ThemeStyles;
|
||||
use cfg_if::cfg_if;
|
||||
use std::fmt;
|
||||
use core::fmt;
|
||||
|
||||
/// Settings to control the color format used for graphical rendering.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
|
||||
|
|
@ -341,17 +345,28 @@ impl MietteHandlerOpts {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::manual_unwrap_or)]
|
||||
pub(crate) fn is_graphical(&self) -> bool {
|
||||
if let Some(force_narrated) = self.force_narrated {
|
||||
!force_narrated
|
||||
} else if let Some(force_graphical) = self.force_graphical {
|
||||
force_graphical
|
||||
} else if let Ok(env) = std::env::var("NO_GRAPHICS") {
|
||||
} else {
|
||||
#[cfg(feature = "fancy-no-backtrace")]
|
||||
{
|
||||
if let Ok(env) = std::env::var("NO_GRAPHICS") {
|
||||
env == "0"
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "fancy-no-backtrace"))]
|
||||
{
|
||||
// fancy-base or fancy-no-syscall without std: default to graphical
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Detects known terminal apps based on env variables and returns true if
|
||||
// they support rendering links.
|
||||
|
|
@ -464,60 +479,63 @@ impl From<HighlighterOption> for MietteHighlighter {
|
|||
}
|
||||
|
||||
mod syscall {
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
#[inline]
|
||||
pub(super) fn terminal_width() -> Option<usize> {
|
||||
cfg_if! {
|
||||
if #[cfg(any(feature = "fancy-no-syscall", miri))] {
|
||||
None
|
||||
} else {
|
||||
#[cfg(all(feature = "fancy-no-backtrace", not(miri)))]
|
||||
{
|
||||
terminal_size::terminal_size().map(|size| size.0 .0 as usize)
|
||||
}
|
||||
#[cfg(any(not(feature = "fancy-no-backtrace"), miri))]
|
||||
{
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn supports_hyperlinks() -> bool {
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "fancy-no-syscall")] {
|
||||
false
|
||||
} else {
|
||||
#[cfg(feature = "fancy-no-backtrace")]
|
||||
{
|
||||
supports_hyperlinks::on(supports_hyperlinks::Stream::Stderr)
|
||||
}
|
||||
#[cfg(not(feature = "fancy-no-backtrace"))]
|
||||
{
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn supports_color() -> bool {
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "fancy-no-syscall")] {
|
||||
false
|
||||
} else {
|
||||
#[cfg(feature = "fancy-no-backtrace")]
|
||||
{
|
||||
supports_color::on(supports_color::Stream::Stderr).is_some()
|
||||
}
|
||||
#[cfg(not(feature = "fancy-no-backtrace"))]
|
||||
{
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn supports_color_has_16m() -> Option<bool> {
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "fancy-no-syscall")] {
|
||||
None
|
||||
} else {
|
||||
#[cfg(feature = "fancy-no-backtrace")]
|
||||
{
|
||||
supports_color::on(supports_color::Stream::Stderr).map(|color| color.has_16m)
|
||||
}
|
||||
#[cfg(not(feature = "fancy-no-backtrace"))]
|
||||
{
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn supports_unicode() -> bool {
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "fancy-no-syscall")] {
|
||||
false
|
||||
} else {
|
||||
#[cfg(feature = "fancy-no-backtrace")]
|
||||
{
|
||||
supports_unicode::on(supports_unicode::Stream::Stderr)
|
||||
}
|
||||
#[cfg(not(feature = "fancy-no-backtrace"))]
|
||||
{
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
use std::fmt;
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt;
|
||||
|
||||
use crate::{protocol::Diagnostic, ReportHandler};
|
||||
|
||||
|
|
@ -34,25 +37,25 @@ impl DebugReportHandler {
|
|||
diagnostic: &dyn Diagnostic,
|
||||
) -> fmt::Result {
|
||||
let mut diag = f.debug_struct("Diagnostic");
|
||||
diag.field("message", &format!("{}", diagnostic));
|
||||
diag.field("message", &alloc::format!("{}", diagnostic));
|
||||
if let Some(code) = diagnostic.code() {
|
||||
diag.field("code", &code.to_string());
|
||||
diag.field("code", &alloc::format!("{}", code));
|
||||
}
|
||||
if let Some(severity) = diagnostic.severity() {
|
||||
diag.field("severity", &format!("{:?}", severity));
|
||||
diag.field("severity", &alloc::format!("{:?}", severity));
|
||||
}
|
||||
if let Some(url) = diagnostic.url() {
|
||||
diag.field("url", &url.to_string());
|
||||
diag.field("url", &alloc::format!("{}", url));
|
||||
}
|
||||
if let Some(help) = diagnostic.help() {
|
||||
diag.field("help", &help.to_string());
|
||||
diag.field("help", &alloc::format!("{}", help));
|
||||
}
|
||||
if let Some(labels) = diagnostic.labels() {
|
||||
let labels: Vec<_> = labels.collect();
|
||||
diag.field("labels", &format!("{:?}", labels));
|
||||
diag.field("labels", &alloc::format!("{:?}", labels));
|
||||
}
|
||||
if let Some(cause) = diagnostic.diagnostic_source() {
|
||||
diag.field("caused by", &format!("{:?}", cause));
|
||||
diag.field("caused by", &alloc::format!("{:?}", cause));
|
||||
}
|
||||
diag.finish()?;
|
||||
writeln!(f)?;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
use std::fmt::{self, Write};
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::format;
|
||||
use alloc::string::{String, ToString};
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::{self, Write};
|
||||
|
||||
use owo_colors::{OwoColorize, Style, StyledList};
|
||||
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
|
||||
|
|
@ -582,7 +588,7 @@ impl GraphicalReportHandler {
|
|||
// The snippets will overlap, so we create one Big Chunky Boi
|
||||
let left_end = left.offset() + left.len();
|
||||
let right_end = right.offset() + right.len();
|
||||
let new_end = std::cmp::max(left_end, right_end);
|
||||
let new_end = core::cmp::max(left_end, right_end);
|
||||
|
||||
let new_span = LabeledSpan::new(
|
||||
left.label().map(String::from),
|
||||
|
|
@ -649,7 +655,7 @@ impl GraphicalReportHandler {
|
|||
num_highlights += 1;
|
||||
}
|
||||
}
|
||||
max_gutter = std::cmp::max(max_gutter, num_highlights);
|
||||
max_gutter = core::cmp::max(max_gutter, num_highlights);
|
||||
}
|
||||
|
||||
// Oh and one more thing: We need to figure out how much room our line
|
||||
|
|
@ -1173,7 +1179,7 @@ impl GraphicalReportHandler {
|
|||
.style(hl.style)
|
||||
.to_string(),
|
||||
);
|
||||
highest = std::cmp::max(highest, end);
|
||||
highest = core::cmp::max(highest, end);
|
||||
|
||||
(hl, vbar_offset)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
use std::fmt::{self, Write};
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::string::ToString;
|
||||
use core::fmt::{self, Write};
|
||||
|
||||
use crate::{
|
||||
diagnostic_chain::DiagnosticChain, protocol::Diagnostic, ReportHandler, Severity, SourceCode,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
use std::fmt;
|
||||
extern crate alloc;
|
||||
|
||||
use core::fmt;
|
||||
|
||||
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
|
||||
|
||||
use crate::diagnostic_chain::DiagnosticChain;
|
||||
use crate::protocol::{Diagnostic, Severity};
|
||||
use crate::{LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
/**
|
||||
[`ReportHandler`] that renders plain text and avoids extraneous graphics.
|
||||
|
|
@ -290,7 +295,7 @@ impl NarratableReportHandler {
|
|||
let context_data = source
|
||||
.read_span(context_span, self.context_lines, self.context_lines)
|
||||
.map_err(|_| fmt::Error)?;
|
||||
let context = std::str::from_utf8(context_data.data()).expect("Bad utf8 detected");
|
||||
let context = core::str::from_utf8(context_data.data()).expect("Bad utf8 detected");
|
||||
let mut line = context_data.line();
|
||||
let mut column = context_data.column();
|
||||
let mut offset = context_data.span().offset();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use std::io::IsTerminal;
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::string::String;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use owo_colors::Style;
|
||||
|
||||
/**
|
||||
|
|
@ -69,6 +71,9 @@ impl GraphicalTheme {
|
|||
|
||||
impl Default for GraphicalTheme {
|
||||
fn default() -> Self {
|
||||
#[cfg(feature = "fancy-no-backtrace")]
|
||||
{
|
||||
use std::io::IsTerminal;
|
||||
match std::env::var("NO_COLOR") {
|
||||
_ if !std::io::stdout().is_terminal() || !std::io::stderr().is_terminal() => {
|
||||
Self::none()
|
||||
|
|
@ -77,6 +82,11 @@ impl Default for GraphicalTheme {
|
|||
_ => Self::unicode(),
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "fancy-no-backtrace"))]
|
||||
{
|
||||
Self::unicode_nocolor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use owo_colors::Style;
|
||||
|
||||
use crate::SpanContents;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,12 @@
|
|||
//! * `syntect-highlighter` - Enables [`syntect`](https://docs.rs/syntect/latest/syntect/) syntax highlighting support via the [`SyntectHighlighter`]
|
||||
//!
|
||||
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
use core::ops::Deref;
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::SpanContents;
|
||||
use owo_colors::Styled;
|
||||
|
|
@ -78,12 +83,12 @@ impl MietteHighlighter {
|
|||
}
|
||||
|
||||
impl Default for MietteHighlighter {
|
||||
#[cfg(feature = "syntect-highlighter")]
|
||||
fn default() -> Self {
|
||||
#[cfg(feature = "syntect-highlighter")]
|
||||
{
|
||||
use std::io::IsTerminal;
|
||||
match std::env::var("NO_COLOR") {
|
||||
_ if !std::io::stdout().is_terminal() || !std::io::stderr().is_terminal() => {
|
||||
//TODO: should use ANSI styling instead of 24-bit truecolor here
|
||||
Self(Arc::new(SyntectHighlighter::default()))
|
||||
}
|
||||
Ok(string) if string != "0" => MietteHighlighter::nocolor(),
|
||||
|
|
@ -91,9 +96,10 @@ impl Default for MietteHighlighter {
|
|||
}
|
||||
}
|
||||
#[cfg(not(feature = "syntect-highlighter"))]
|
||||
fn default() -> Self {
|
||||
{
|
||||
MietteHighlighter::nocolor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Highlighter + Send + Sync + 'static> From<T> for MietteHighlighter {
|
||||
|
|
@ -102,8 +108,8 @@ impl<T: Highlighter + Send + Sync + 'static> From<T> for MietteHighlighter {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for MietteHighlighter {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
impl core::fmt::Debug for MietteHighlighter {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "MietteHighlighter(...)")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
use core::str;
|
||||
use std::path::Path;
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
// all syntect imports are explicitly qualified, but their paths are shortened for convenience
|
||||
#[allow(clippy::module_inception)]
|
||||
mod syntect {
|
||||
|
|
@ -97,7 +103,7 @@ impl SyntectHighlighter {
|
|||
}
|
||||
// finally, attempt to guess syntax based on first line
|
||||
self.syntax_set.find_syntax_by_first_line(
|
||||
std::str::from_utf8(contents.data())
|
||||
core::str::from_utf8(contents.data())
|
||||
.ok()?
|
||||
.split('\n')
|
||||
.next()?,
|
||||
|
|
|
|||
48
src/lib.rs
48
src/lib.rs
|
|
@ -1,6 +1,13 @@
|
|||
#![no_std]
|
||||
#![deny(missing_docs, missing_debug_implementations, nonstandard_style)]
|
||||
#![warn(unreachable_pub, rust_2018_idioms)]
|
||||
#![deny(
|
||||
clippy::alloc_instead_of_core,
|
||||
clippy::std_instead_of_core,
|
||||
clippy::std_instead_of_alloc
|
||||
)]
|
||||
#![allow(unexpected_cfgs)]
|
||||
|
||||
//! You run miette? You run her code like the software? Oh. Oh! Error code for
|
||||
//! coder! Error code for One Thousand Lines!
|
||||
//!
|
||||
|
|
@ -58,8 +65,8 @@
|
|||
//!
|
||||
//! ## Features
|
||||
//!
|
||||
//! - Generic [`Diagnostic`] protocol, compatible (and dependent on)
|
||||
//! [`std::error::Error`].
|
||||
//! - Generic [`Diagnostic`] protocol, compatible with `std::error::Error`.
|
||||
//! Works without the standard library: Just turn off the default `std` feature and you can use `miette` in places like embedded systems or web browsers that don't have the full standard library. You still need `alloc` for memory management.
|
||||
//! - Unique error codes on every [`Diagnostic`].
|
||||
//! - Custom links to get more details on error codes.
|
||||
//! - Super handy derive macro for defining diagnostic metadata.
|
||||
|
|
@ -93,9 +100,23 @@
|
|||
//! $ cargo add miette --features fancy
|
||||
//! ```
|
||||
//!
|
||||
//! For computers without the standard library (like microcontrollers or web browsers):
|
||||
//!
|
||||
//! ```sh
|
||||
//! $ cargo add miette --no-default-features --features derive
|
||||
//! ```
|
||||
//!
|
||||
//! Available features you can turn on or off:
|
||||
//! - `std` (on by default): Use the standard library
|
||||
//! - `derive`: Lets you automatically create error types
|
||||
//! - `fancy`: Shows pretty error messages with colors
|
||||
//! - `fancy-no-syscall`: Pretty errors without using system calls
|
||||
//! - `fancy-no-backtrace`: Pretty errors without showing the call stack
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! ```rust
|
||||
//! # extern crate alloc;
|
||||
//! /*
|
||||
//! You can derive a `Diagnostic` from any `std::error::Error` type.
|
||||
//!
|
||||
|
|
@ -193,6 +214,7 @@
|
|||
//! the trait directly, just like with `std::error::Error`.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # extern crate alloc;
|
||||
//! // lib/error.rs
|
||||
//! use miette::{Diagnostic, SourceSpan};
|
||||
//! use thiserror::Error;
|
||||
|
|
@ -360,6 +382,7 @@
|
|||
//! attribute:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # extern crate alloc;
|
||||
//! use miette::Diagnostic;
|
||||
//! use thiserror::Error;
|
||||
//!
|
||||
|
|
@ -380,6 +403,7 @@
|
|||
//! (very high quality and detailed!) documentation on this diagnostic:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # extern crate alloc;
|
||||
//! use miette::Diagnostic;
|
||||
//! use thiserror::Error;
|
||||
//!
|
||||
|
|
@ -410,6 +434,7 @@
|
|||
//! `derive(Diagnostic)` macro:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # extern crate alloc;
|
||||
//! use miette::{Diagnostic, SourceSpan};
|
||||
//! use thiserror::Error;
|
||||
//!
|
||||
|
|
@ -448,6 +473,7 @@
|
|||
//! enum variants:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # extern crate alloc;
|
||||
//! use miette::Diagnostic;
|
||||
//! use thiserror::Error;
|
||||
//!
|
||||
|
|
@ -461,6 +487,7 @@
|
|||
//! your diagnostic:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # extern crate alloc;
|
||||
//! use miette::Diagnostic;
|
||||
//! use thiserror::Error;
|
||||
//!
|
||||
|
|
@ -499,6 +526,7 @@
|
|||
//! `Diagnostic` type:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # extern crate alloc;
|
||||
//! use miette::Diagnostic;
|
||||
//! use thiserror::Error;
|
||||
//!
|
||||
|
|
@ -517,6 +545,7 @@
|
|||
//! method for that:
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! # extern crate alloc;
|
||||
//! use miette::{Diagnostic, SourceSpan};
|
||||
//! use thiserror::Error;
|
||||
//!
|
||||
|
|
@ -549,6 +578,7 @@
|
|||
//! emitted at the same time:
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! # extern crate alloc;
|
||||
//! use miette::{Diagnostic, Report, SourceSpan};
|
||||
//! use thiserror::Error;
|
||||
//!
|
||||
|
|
@ -610,6 +640,7 @@
|
|||
//! will likely want to use _both_:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # extern crate alloc;
|
||||
//! use miette::Diagnostic;
|
||||
//! use thiserror::Error;
|
||||
//!
|
||||
|
|
@ -815,6 +846,19 @@
|
|||
//! and some from [`thiserror`](https://github.com/dtolnay/thiserror), also
|
||||
//! under the Apache License. Some code is taken from
|
||||
//! [`ariadne`](https://github.com/zesterer/ariadne), which is MIT licensed.
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
pub use core::error::Error as StdError;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod __alloc {
|
||||
extern crate alloc;
|
||||
pub use alloc::borrow;
|
||||
pub use alloc::boxed::Box;
|
||||
}
|
||||
|
||||
#[cfg(feature = "derive")]
|
||||
pub use miette_derive::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
use std::{
|
||||
error::Error,
|
||||
fmt::{Debug, Display},
|
||||
};
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use core::error::Error;
|
||||
use core::fmt::{Debug, Display};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -39,7 +42,7 @@ pub struct MietteDiagnostic {
|
|||
}
|
||||
|
||||
impl Display for MietteDiagnostic {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{}", &self.message)
|
||||
}
|
||||
}
|
||||
|
|
@ -183,7 +186,7 @@ impl MietteDiagnostic {
|
|||
/// assert_eq!(diag.labels, Some(vec![label]));
|
||||
/// ```
|
||||
pub fn with_label(mut self, label: impl Into<LabeledSpan>) -> Self {
|
||||
self.labels = Some(vec![label.into()]);
|
||||
self.labels = Some(Vec::from([label.into()]));
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -261,6 +264,7 @@ impl MietteDiagnostic {
|
|||
#[cfg(feature = "serde")]
|
||||
#[test]
|
||||
fn test_serialize_miette_diagnostic() {
|
||||
use alloc::format;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::diagnostic;
|
||||
|
|
@ -311,6 +315,7 @@ fn test_serialize_miette_diagnostic() {
|
|||
#[cfg(feature = "serde")]
|
||||
#[test]
|
||||
fn test_deserialize_miette_diagnostic() {
|
||||
use alloc::format;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::diagnostic;
|
||||
|
|
|
|||
|
|
@ -10,8 +10,14 @@ pub struct NamedSource<S: SourceCode + 'static> {
|
|||
language: Option<String>,
|
||||
}
|
||||
|
||||
impl<S: SourceCode> std::fmt::Debug for NamedSource<S> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use alloc::string::ToString;
|
||||
|
||||
impl<S: SourceCode> core::fmt::Debug for NamedSource<S> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("NamedSource")
|
||||
.field("name", &self.name)
|
||||
.field("source", &"<redacted>")
|
||||
|
|
|
|||
20
src/panic.rs
20
src/panic.rs
|
|
@ -1,10 +1,24 @@
|
|||
use std::{error::Error, fmt::Display};
|
||||
// `fancy` feature requires std, so std imports are fine here.
|
||||
#![allow(
|
||||
clippy::std_instead_of_core,
|
||||
clippy::std_instead_of_alloc,
|
||||
clippy::alloc_instead_of_core
|
||||
)]
|
||||
|
||||
use std::boxed::Box;
|
||||
use std::{
|
||||
eprintln,
|
||||
error::Error,
|
||||
fmt::Display,
|
||||
format,
|
||||
string::{String, ToString},
|
||||
};
|
||||
|
||||
use backtrace::Backtrace;
|
||||
|
||||
use crate::{Context, Diagnostic, Result};
|
||||
|
||||
/// Tells miette to render panics using its rendering engine.
|
||||
/// Makes miette show pretty error messages when your program crashes.
|
||||
pub fn set_panic_hook() {
|
||||
std::panic::set_hook(Box::new(move |info| {
|
||||
let mut message = "Something went wrong".to_string();
|
||||
|
|
@ -104,7 +118,7 @@ impl Panic {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::error::Error;
|
||||
use std::{borrow::ToOwned, error::Error};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,21 +3,26 @@ This module defines the core of the miette protocol: a series of types and
|
|||
traits that you can implement to get access to miette's (and related library's)
|
||||
full reporting and such features.
|
||||
*/
|
||||
use std::{
|
||||
fmt::{self, Display},
|
||||
fs,
|
||||
panic::Location,
|
||||
};
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use core::fmt::{self, Display};
|
||||
use core::ops;
|
||||
#[cfg(feature = "std")]
|
||||
use core::panic::Location;
|
||||
#[cfg(feature = "std")]
|
||||
use std::fs;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{DiagnosticError, MietteError};
|
||||
use crate::MietteError;
|
||||
|
||||
/// Adds rich metadata to your Error that can be used by
|
||||
/// [`Report`](crate::Report) to print really nice and human-friendly error
|
||||
/// messages.
|
||||
pub trait Diagnostic: std::error::Error {
|
||||
pub trait Diagnostic: crate::StdError {
|
||||
/// Unique diagnostic code that can be used to look up more information
|
||||
/// about this `Diagnostic`. Ideally also globally unique, and documented
|
||||
/// in the toplevel crate's documentation for easy searching. Rust path
|
||||
|
|
@ -72,14 +77,10 @@ pub trait Diagnostic: std::error::Error {
|
|||
macro_rules! box_error_impls {
|
||||
($($box_type:ty),*) => {
|
||||
$(
|
||||
impl std::error::Error for $box_type {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
impl crate::StdError for $box_type {
|
||||
fn source(&self) -> Option<&(dyn crate::StdError + 'static)> {
|
||||
(**self).source()
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&dyn std::error::Error> {
|
||||
self.source()
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
|
@ -94,7 +95,7 @@ box_error_impls! {
|
|||
macro_rules! box_borrow_impls {
|
||||
($($box_type:ty),*) => {
|
||||
$(
|
||||
impl std::borrow::Borrow<dyn Diagnostic> for $box_type {
|
||||
impl core::borrow::Borrow<dyn Diagnostic> for $box_type {
|
||||
fn borrow(&self) -> &(dyn Diagnostic + 'static) {
|
||||
self.as_ref()
|
||||
}
|
||||
|
|
@ -152,7 +153,7 @@ impl From<String> for Box<dyn Diagnostic + Send + Sync> {
|
|||
fn from(s: String) -> Self {
|
||||
struct StringError(String);
|
||||
|
||||
impl std::error::Error for StringError {}
|
||||
impl crate::StdError for StringError {}
|
||||
impl Diagnostic for StringError {}
|
||||
|
||||
impl Display for StringError {
|
||||
|
|
@ -172,8 +173,12 @@ impl From<String> for Box<dyn Diagnostic + Send + Sync> {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Box<dyn std::error::Error + Send + Sync>> for Box<dyn Diagnostic + Send + Sync> {
|
||||
fn from(s: Box<dyn std::error::Error + Send + Sync>) -> Self {
|
||||
#[cfg(feature = "std")]
|
||||
use crate::DiagnosticError;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<Box<dyn core::error::Error + Send + Sync>> for Box<dyn Diagnostic + Send + Sync> {
|
||||
fn from(s: Box<dyn core::error::Error + Send + Sync>) -> Self {
|
||||
Box::new(DiagnosticError(s))
|
||||
}
|
||||
}
|
||||
|
|
@ -369,6 +374,7 @@ impl LabeledSpan {
|
|||
#[cfg(feature = "serde")]
|
||||
#[test]
|
||||
fn test_serialize_labeled_span() {
|
||||
use alloc::string::ToString;
|
||||
use serde_json::json;
|
||||
|
||||
assert_eq!(
|
||||
|
|
@ -392,6 +398,7 @@ fn test_serialize_labeled_span() {
|
|||
#[cfg(feature = "serde")]
|
||||
#[test]
|
||||
fn test_deserialize_labeled_span() {
|
||||
use alloc::string::ToString;
|
||||
use serde_json::json;
|
||||
|
||||
let span: LabeledSpan = serde_json::from_value(json!({
|
||||
|
|
@ -594,8 +601,8 @@ impl From<(SourceOffset, usize)> for SourceSpan {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::Range<ByteOffset>> for SourceSpan {
|
||||
fn from(range: std::ops::Range<ByteOffset>) -> Self {
|
||||
impl From<ops::Range<ByteOffset>> for SourceSpan {
|
||||
fn from(range: ops::Range<ByteOffset>) -> Self {
|
||||
Self {
|
||||
offset: range.start.into(),
|
||||
length: range.len(),
|
||||
|
|
@ -603,12 +610,12 @@ impl From<std::ops::Range<ByteOffset>> for SourceSpan {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeInclusive<ByteOffset>> for SourceSpan {
|
||||
impl From<ops::RangeInclusive<ByteOffset>> for SourceSpan {
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the total length of the inclusive range would overflow a
|
||||
/// `usize`. This will only occur with the range `0..=usize::MAX`.
|
||||
fn from(range: std::ops::RangeInclusive<ByteOffset>) -> Self {
|
||||
fn from(range: ops::RangeInclusive<ByteOffset>) -> Self {
|
||||
let (start, end) = range.clone().into_inner();
|
||||
Self {
|
||||
offset: start.into(),
|
||||
|
|
@ -715,6 +722,7 @@ impl SourceOffset {
|
|||
/// you're shipping binaries for your application, you'll want to ignore
|
||||
/// the Err case or otherwise report it.
|
||||
#[track_caller]
|
||||
#[cfg(feature = "std")]
|
||||
pub fn from_current_location() -> Result<(String, Self), MietteError> {
|
||||
let loc = Location::caller();
|
||||
Ok((
|
||||
|
|
|
|||
|
|
@ -1,7 +1,16 @@
|
|||
/*!
|
||||
Default trait implementations for [`SourceCode`].
|
||||
*/
|
||||
use std::{borrow::Cow, collections::VecDeque, fmt::Debug, sync::Arc};
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::borrow::Cow;
|
||||
use alloc::borrow::ToOwned;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::collections::VecDeque;
|
||||
use alloc::string::String;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::Debug;
|
||||
|
||||
use crate::{MietteError, MietteSpanContents, SourceCode, SourceSpan, SpanContents};
|
||||
|
||||
|
|
@ -205,7 +214,7 @@ mod tests {
|
|||
fn basic() -> Result<(), MietteError> {
|
||||
let src = String::from("foo\n");
|
||||
let contents = src.read_span(&(0, 4).into(), 0, 0)?;
|
||||
assert_eq!("foo\n", std::str::from_utf8(contents.data()).unwrap());
|
||||
assert_eq!("foo\n", core::str::from_utf8(contents.data()).unwrap());
|
||||
assert_eq!(0, contents.line());
|
||||
assert_eq!(0, contents.column());
|
||||
Ok(())
|
||||
|
|
@ -215,7 +224,7 @@ mod tests {
|
|||
fn shifted() -> Result<(), MietteError> {
|
||||
let src = String::from("foobar");
|
||||
let contents = src.read_span(&(3, 3).into(), 1, 1)?;
|
||||
assert_eq!("foobar", std::str::from_utf8(contents.data()).unwrap());
|
||||
assert_eq!("foobar", core::str::from_utf8(contents.data()).unwrap());
|
||||
assert_eq!(0, contents.line());
|
||||
assert_eq!(0, contents.column());
|
||||
Ok(())
|
||||
|
|
@ -225,7 +234,7 @@ mod tests {
|
|||
fn middle() -> Result<(), MietteError> {
|
||||
let src = String::from("foo\nbar\nbaz\n");
|
||||
let contents = src.read_span(&(4, 4).into(), 0, 0)?;
|
||||
assert_eq!("bar\n", std::str::from_utf8(contents.data()).unwrap());
|
||||
assert_eq!("bar\n", core::str::from_utf8(contents.data()).unwrap());
|
||||
assert_eq!(1, contents.line());
|
||||
assert_eq!(0, contents.column());
|
||||
Ok(())
|
||||
|
|
@ -235,7 +244,7 @@ mod tests {
|
|||
fn middle_of_line() -> Result<(), MietteError> {
|
||||
let src = String::from("foo\nbarbar\nbaz\n");
|
||||
let contents = src.read_span(&(7, 4).into(), 0, 0)?;
|
||||
assert_eq!("bar\n", std::str::from_utf8(contents.data()).unwrap());
|
||||
assert_eq!("bar\n", core::str::from_utf8(contents.data()).unwrap());
|
||||
assert_eq!(1, contents.line());
|
||||
assert_eq!(3, contents.column());
|
||||
Ok(())
|
||||
|
|
@ -245,7 +254,7 @@ mod tests {
|
|||
fn with_crlf() -> Result<(), MietteError> {
|
||||
let src = String::from("foo\r\nbar\r\nbaz\r\n");
|
||||
let contents = src.read_span(&(5, 5).into(), 0, 0)?;
|
||||
assert_eq!("bar\r\n", std::str::from_utf8(contents.data()).unwrap());
|
||||
assert_eq!("bar\r\n", core::str::from_utf8(contents.data()).unwrap());
|
||||
assert_eq!(1, contents.line());
|
||||
assert_eq!(0, contents.column());
|
||||
Ok(())
|
||||
|
|
@ -257,7 +266,7 @@ mod tests {
|
|||
let contents = src.read_span(&(8, 3).into(), 1, 1)?;
|
||||
assert_eq!(
|
||||
"foo\nbar\nbaz\n",
|
||||
std::str::from_utf8(contents.data()).unwrap()
|
||||
core::str::from_utf8(contents.data()).unwrap()
|
||||
);
|
||||
assert_eq!(1, contents.line());
|
||||
assert_eq!(0, contents.column());
|
||||
|
|
@ -270,7 +279,7 @@ mod tests {
|
|||
let contents = src.read_span(&(9, 11).into(), 1, 1)?;
|
||||
assert_eq!(
|
||||
"\nfoo\nbar\nbaz\n\n",
|
||||
std::str::from_utf8(contents.data()).unwrap()
|
||||
core::str::from_utf8(contents.data()).unwrap()
|
||||
);
|
||||
assert_eq!(2, contents.line());
|
||||
assert_eq!(0, contents.column());
|
||||
|
|
@ -285,7 +294,7 @@ mod tests {
|
|||
let contents = src.read_span(&(2, 0).into(), 2, 2)?;
|
||||
assert_eq!(
|
||||
"one\ntwo\n\n",
|
||||
std::str::from_utf8(contents.data()).unwrap()
|
||||
core::str::from_utf8(contents.data()).unwrap()
|
||||
);
|
||||
assert_eq!(0, contents.line());
|
||||
assert_eq!(0, contents.column());
|
||||
|
|
|
|||
|
|
@ -83,7 +83,9 @@ fn check_colors<F: Fn(MietteHandlerOpts) -> MietteHandlerOpts>(
|
|||
//
|
||||
// Since environment variables are shared for the entire process, we need
|
||||
// to ensure that only one test that modifies these env vars runs at a time.
|
||||
let lock = COLOR_ENV_VARS.lock().unwrap();
|
||||
let lock = COLOR_ENV_VARS
|
||||
.lock()
|
||||
.unwrap_or_else(|poisoned| poisoned.into_inner());
|
||||
|
||||
let guards = (
|
||||
EnvVarGuard::new("NO_COLOR"),
|
||||
|
|
|
|||
|
|
@ -10,5 +10,5 @@ pub fn bail_fmt() -> Result<()> {
|
|||
}
|
||||
|
||||
pub fn bail_error() -> Result<()> {
|
||||
bail!(io::Error::new(io::ErrorKind::Other, "oh no!"));
|
||||
bail!(io::Error::other("oh no!"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(unused_assignments)] // some fields unused when feature="fancy"
|
||||
|
||||
use miette::{Diagnostic, Report, Severity, SourceSpan};
|
||||
use thiserror::Error;
|
||||
|
||||
|
|
@ -244,6 +246,7 @@ fn help_field() {
|
|||
#[diagnostic()]
|
||||
struct Foo<'a> {
|
||||
#[help]
|
||||
#[allow(unused_assignments)]
|
||||
do_this: Option<&'a str>,
|
||||
}
|
||||
|
||||
|
|
@ -293,6 +296,7 @@ fn test_snippet_named_struct() {
|
|||
#[error("welp")]
|
||||
#[diagnostic(code(foo::bar::baz))]
|
||||
#[allow(dead_code)]
|
||||
#[allow(unused_assignments)]
|
||||
struct Foo<'a> {
|
||||
#[source_code]
|
||||
src: &'a str,
|
||||
|
|
@ -401,6 +405,7 @@ const SNIPPET_TEXT: &str = "hello from miette";
|
|||
help("help"),
|
||||
severity(Warning)
|
||||
)]
|
||||
#[allow(unused_assignments)]
|
||||
struct ForwardsTo {
|
||||
#[source_code]
|
||||
src: String,
|
||||
|
|
@ -501,6 +506,7 @@ fn test_forward_struct_named() {
|
|||
help("{help}"),
|
||||
forward(span)
|
||||
)]
|
||||
#[allow(unused_assignments)]
|
||||
struct Struct<'a> {
|
||||
span: ForwardsTo,
|
||||
help: &'a str,
|
||||
|
|
@ -534,6 +540,7 @@ fn test_forward_enum_named() {
|
|||
enum Enum<'a> {
|
||||
#[error("help: {help_text}")]
|
||||
#[diagnostic(code(foo::bar::overridden), help("{help_text}"), forward(span))]
|
||||
#[allow(unused_assignments)]
|
||||
Variant {
|
||||
span: ForwardsTo,
|
||||
help_text: &'a str,
|
||||
|
|
@ -595,6 +602,7 @@ fn test_unit_enum_display() {
|
|||
fn test_optional_source_code() {
|
||||
#[derive(Debug, Diagnostic, Error)]
|
||||
#[error("struct with optional source")]
|
||||
#[allow(unused_assignments)]
|
||||
struct Struct {
|
||||
#[source_code]
|
||||
src: Option<String>,
|
||||
|
|
@ -607,6 +615,7 @@ fn test_optional_source_code() {
|
|||
.is_some());
|
||||
|
||||
#[derive(Debug, Diagnostic, Error)]
|
||||
#[allow(unused_assignments)]
|
||||
enum Enum {
|
||||
#[error("variant1 with optional source")]
|
||||
Variant1 {
|
||||
|
|
|
|||
|
|
@ -42,13 +42,13 @@ fn test_boxed_str_stderr() {
|
|||
#[test]
|
||||
fn test_boxed_thiserror() {
|
||||
let error = MyError {
|
||||
source: io::Error::new(io::ErrorKind::Other, "oh no!"),
|
||||
source: io::Error::other("oh no!"),
|
||||
};
|
||||
let report: Report = miette!(error);
|
||||
assert_eq!("oh no!", report.source().unwrap().to_string());
|
||||
|
||||
let error = MyError {
|
||||
source: io::Error::new(io::ErrorKind::Other, "oh no!!!!"),
|
||||
source: io::Error::other("oh no!!!!"),
|
||||
};
|
||||
let error: Box<dyn Diagnostic + Send + Sync + 'static> = Box::new(error);
|
||||
let report = Report::new_boxed(error);
|
||||
|
|
@ -203,7 +203,7 @@ fn test_boxed_custom_diagnostic() {
|
|||
|
||||
let related = CustomDiagnostic::new();
|
||||
let main_diagnostic = CustomDiagnostic::new()
|
||||
.with_source(io::Error::new(io::ErrorKind::Other, "oh no!"))
|
||||
.with_source(io::Error::other("oh no!"))
|
||||
.with_related(related);
|
||||
|
||||
let report = Report::new_boxed(Box::new(main_diagnostic));
|
||||
|
|
@ -211,7 +211,7 @@ fn test_boxed_custom_diagnostic() {
|
|||
|
||||
let related = CustomDiagnostic::new();
|
||||
let main_diagnostic = CustomDiagnostic::new()
|
||||
.with_source(io::Error::new(io::ErrorKind::Other, "oh no!"))
|
||||
.with_source(io::Error::other("oh no!"))
|
||||
.with_related(related);
|
||||
let main_diagnostic = Box::new(main_diagnostic) as Box<dyn Diagnostic + Send + Sync + 'static>;
|
||||
let report = miette!(main_diagnostic);
|
||||
|
|
@ -228,7 +228,7 @@ fn test_boxed_custom_diagnostic() {
|
|||
#[test]
|
||||
fn test_boxed_sources() {
|
||||
let error = MyError {
|
||||
source: io::Error::new(io::ErrorKind::Other, "oh no!"),
|
||||
source: io::Error::other("oh no!"),
|
||||
};
|
||||
let error = Box::<dyn Diagnostic + Send + Sync>::from(error);
|
||||
let error: Report = miette!(error).wrap_err("it failed");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// Testing of the `diagnostic` attr used by derive(Diagnostic)
|
||||
|
||||
use miette::{Diagnostic, LabeledSpan, NamedSource, SourceSpan};
|
||||
use thiserror::Error;
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ fn test_fmt_source() {
|
|||
#[test]
|
||||
#[ignore = "Again with the io::Error source issue?"]
|
||||
fn test_io_source() {
|
||||
let io = io::Error::new(io::ErrorKind::Other, "oh no!");
|
||||
let io = io::Error::other("oh no!");
|
||||
let error: Report = miette!(TestError::Io(io));
|
||||
assert_eq!("oh no!", error.source().unwrap().to_string());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue