diff --git a/Cargo.toml b/Cargo.toml index f89f14b..cbabc78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,9 +13,11 @@ rust-version = "1.82.0" exclude = ["images/", "tests/", "miette-derive/"] [dependencies] +thiserror = "2.0.11" miette-derive = { path = "miette-derive", version = "=7.6.0", optional = true } -unicode-width = "0.2.0" +unicode-width = { version = "0.2.0", default-features = false } cfg-if = "1.0.0" +spin = { version = "0.9", default-features = false, features = ["mutex", "spin_mutex", "lazy"] } owo-colors = { version = "4.0.0", optional = true } textwrap = { version = "0.16.0", default-features = false, features = ["unicode-linebreak", "unicode-width"], optional = true } @@ -29,9 +31,11 @@ serde = { version = "1.0.196", features = ["derive"], optional = true } syntect = { version = "5.1.0", optional = true } [dev-dependencies] -thiserror = "2.0.11" semver = "1.0.21" +[build-dependencies] +rustc_version = "0.2" + # Eyre devdeps futures = { version = "0.3", default-features = false } indenter = "0.3.3" @@ -45,7 +49,8 @@ serde_json = "1.0.113" strip-ansi-escapes = "0.2.0" [features] -default = ["derive"] +default = ["derive", "std"] +std = ["thiserror/std", "fancy-no-syscall"] derive = ["dep:miette-derive"] no-format-args-capture = [] fancy-base = [ diff --git a/miette-derive/src/code.rs b/miette-derive/src/code.rs index 22dc795..8ebe920 100644 --- a/miette-derive/src/code.rs +++ b/miette-derive/src/code.rs @@ -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 { .. } => Option::Some(alloc::boxed::Box::new(#code)), } } syn::Fields::Unnamed(_) => { - quote! { Self::#ident(..) => std::option::Option::Some(std::boxed::Box::new(#code)), } + quote! { Self::#ident(..) => Option::Some(alloc::boxed::Box::new(#code)), } } syn::Fields::Unit => { - quote! { Self::#ident => std::option::Option::Some(std::boxed::Box::new(#code)), } + quote! { Self::#ident => Option::Some(alloc::boxed::Box::new(#code)), } } }) }, @@ -72,8 +72,8 @@ impl Code { pub(crate) fn gen_struct(&self) -> Option { let code = &self.0; Some(quote! { - fn code(&self) -> std::option::Option> { - std::option::Option::Some(std::boxed::Box::new(#code)) + fn code(&self) -> Option> { + Some(alloc::boxed::Box::new(#code)) } }) } diff --git a/miette-derive/src/diagnostic_source.rs b/miette-derive/src/diagnostic_source.rs index 1104eb7..7864e4a 100644 --- a/miette-derive/src/diagnostic_source.rs +++ b/miette-derive/src/diagnostic_source.rs @@ -59,7 +59,7 @@ impl DiagnosticSource { }; quote! { Self::#ident #display_pat => { - std::option::Option::Some(std::borrow::Borrow::borrow(#rel)) + Some(alloc::borrow::Borrow::borrow(#rel)) } } }) @@ -70,8 +70,8 @@ impl DiagnosticSource { pub(crate) fn gen_struct(&self) -> Option { 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) -> Option<&'a dyn miette::Diagnostic> { + Some(alloc::borrow::Borrow::borrow(&self.#rel)) } }) } diff --git a/miette-derive/src/forward.rs b/miette-derive/src/forward.rs index d170366..cdc658f 100644 --- a/miette-derive/src/forward.rs +++ b/miette-derive/src/forward.rs @@ -58,34 +58,34 @@ impl WhichFn { pub fn signature(&self) -> TokenStream { match self { Self::Code => quote! { - fn code(& self) -> std::option::Option> + fn code(& self) -> Option> }, Self::Help => quote! { - fn help(& self) -> std::option::Option> + fn help(& self) -> Option> }, Self::Url => quote! { - fn url(& self) -> std::option::Option> + fn url(& self) -> Option> }, Self::Severity => quote! { - fn severity(&self) -> std::option::Option + fn severity(&self) -> Option }, Self::Related => quote! { - fn related(&self) -> std::option::Option + '_>> + fn related(&self) -> Option + '_>> }, Self::Labels => quote! { - fn labels(&self) -> std::option::Option + '_>> + fn labels(&self) -> Option + '_>> }, 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 } } } diff --git a/miette-derive/src/help.rs b/miette-derive/src/help.rs index 1c21054..0169027 100644 --- a/miette-derive/src/help.rs +++ b/miette-derive/src/help.rs @@ -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(alloc::boxed::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 { std::boxed::Box::new(format!("{}", #var)) }) + miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(&#help).as_ref().map(|#var| -> alloc::boxed::Box { alloc::boxed::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> { + fn help(&self) -> Option> { #[allow(unused_variables, deprecated)] let Self #display_pat = self; - std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args))) + Option::Some(alloc::boxed::Box::new(format!(#fmt #args))) } }) } Help::Field(member, ty) => { let var = quote! { __miette_internal_var }; Some(quote! { - fn help(&self) -> std::option::Option> { + fn help(&self) -> Option> { #[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 { std::boxed::Box::new(format!("{}", #var)) }) + miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(&self.#member).as_ref().map(|#var| -> alloc::boxed::Box { alloc::boxed::Box::new(format!("{}", #var)) }) } }) } diff --git a/miette-derive/src/label.rs b/miette-derive/src/label.rs index ab2ceac..28db920 100644 --- a/miette-derive/src/label.rs +++ b/miette-derive/src/label.rs @@ -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 + '_>> { + fn labels(&self) -> Option + '_>> { 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(alloc::boxed::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(alloc::boxed::Box::new(labels_iter.filter(Option::is_some).map(Option::unwrap))) } }), } diff --git a/miette-derive/src/related.rs b/miette-derive/src/related.rs index 9b7f9e1..8158ea6 100644 --- a/miette-derive/src/related.rs +++ b/miette-derive/src/related.rs @@ -55,7 +55,7 @@ impl Related { }; quote! { Self::#ident #display_pat => { - std::option::Option::Some(std::boxed::Box::new( + Option::Some(alloc::boxed::Box::new( #rel.iter().map(|x| -> &(dyn miette::Diagnostic) { &*x }) )) } @@ -68,9 +68,9 @@ impl Related { pub(crate) fn gen_struct(&self) -> Option { let rel = &self.0; Some(quote! { - fn related<'a>(&'a self) -> std::option::Option + 'a>> { - use ::core::borrow::Borrow; - std::option::Option::Some(std::boxed::Box::new( + fn related<'a>(&'a self) -> Option + 'a>> { + use alloc::borrow::Borrow; + Option::Some(alloc::boxed::Box::new( self.#rel.iter().map(|x| -> &(dyn miette::Diagnostic) { &*x.borrow() }) )) } diff --git a/miette-derive/src/severity.rs b/miette-derive/src/severity.rs index 4f26e4e..40f1bd7 100644 --- a/miette-derive/src/severity.rs +++ b/miette-derive/src/severity.rs @@ -72,7 +72,7 @@ impl Severity { syn::Fields::Unit => quote! {}, }; Some( - quote! { Self::#ident #fields => std::option::Option::Some(miette::Severity::#severity), }, + quote! { Self::#ident #fields => Option::Some(miette::Severity::#severity), }, ) }, ) diff --git a/miette-derive/src/source_code.rs b/miette-derive/src/source_code.rs index e1b85ab..f130953 100644 --- a/miette-derive/src/source_code.rs +++ b/miette-derive/src/source_code.rs @@ -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 { diff --git a/miette-derive/src/url.rs b/miette-derive/src/url.rs index 734d1a4..2583a1c 100644 --- a/miette-derive/src/url.rs +++ b/miette-derive/src/url.rs @@ -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(alloc::boxed::Box::new(format!(#fmt #args))), }) }, ) @@ -129,10 +129,10 @@ impl Url { } }; Some(quote! { - fn url(&self) -> std::option::Option> { + fn url(&self) -> Option> { #[allow(unused_variables, deprecated)] let Self #pat = self; - std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args))) + Option::Some(alloc::boxed::Box::new(format!(#fmt #args))) } }) } diff --git a/src/chain.rs b/src/chain.rs index 369ff7d..e21d82a 100644 --- a/src/chain.rs +++ b/src/chain.rs @@ -3,8 +3,13 @@ Iterate over error `.source()` chains. NOTE: This module is taken wholesale from . */ +extern crate alloc; + +#[cfg(feature = "std")] use std::error::Error as StdError; -use std::vec; +#[cfg(not(feature = "std"))] +use crate::StdError; +use alloc::vec::{self, Vec}; use ChainState::*; diff --git a/src/diagnostic_chain.rs b/src/diagnostic_chain.rs index 996fdba..e9dcccd 100644 --- a/src/diagnostic_chain.rs +++ b/src/diagnostic_chain.rs @@ -2,7 +2,10 @@ Iterate over error `.diagnostic_source()` chains. */ +extern crate alloc; + use crate::protocol::Diagnostic; +use alloc::string::ToString; /// Iterator of a chain of cause errors. #[derive(Clone, Default)] @@ -18,7 +21,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 +62,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 +77,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 +86,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), diff --git a/src/diagnostic_impls.rs b/src/diagnostic_impls.rs index aebe56b..4bb7345 100644 --- a/src/diagnostic_impls.rs +++ b/src/diagnostic_impls.rs @@ -1,10 +1,14 @@ /*! Default trait implementations for [`Diagnostic`]. */ +extern crate alloc; -use std::{convert::Infallible, fmt::Display}; +use core::{convert::Infallible, fmt::Display}; +use alloc::boxed::Box; -use crate::{Diagnostic, LabeledSpan, Severity, SourceCode}; +use crate::{Diagnostic, LabeledSpan, Severity, SourceCode, StdError}; + +impl StdError for Infallible {} impl Diagnostic for Infallible { fn code<'a>(&'a self) -> Option> { diff --git a/src/error.rs b/src/error.rs index f77ce1e..5fab5b8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,8 +1,13 @@ -use std::{ - error::Error, - fmt::{self, Display}, - io, -}; +extern crate alloc; + +#[cfg(feature = "std")] +use std::io; +#[cfg(feature = "std")] +use std::error::Error; +#[cfg(not(feature = "std"))] +use crate::StdError as Error; +use core::fmt::{self, Display}; +use alloc::boxed::Box; use crate::Diagnostic; @@ -11,8 +16,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 +29,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 +41,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 for MietteError { fn from(value: io::Error) -> Self { Self::IoError(value) @@ -49,6 +58,7 @@ impl From for MietteError { impl Diagnostic for MietteError { fn code<'a>(&'a self) -> Option> { 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 +66,7 @@ impl Diagnostic for MietteError { fn help<'a>(&'a self) -> Option> { 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,10 +77,11 @@ impl Diagnostic for MietteError { fn url<'a>(&'a self) -> Option> { 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, ))) @@ -78,12 +90,18 @@ impl Diagnostic for MietteError { #[cfg(test)] pub(crate) mod tests { - use std::{error::Error, io::ErrorKind}; + #[cfg(feature = "std")] + use std::io::ErrorKind; + #[cfg(not(feature = "std"))] + use crate::StdError as Error; use super::*; #[derive(Debug)] + #[cfg(feature = "std")] pub(crate) struct TestError(pub(crate) io::Error); + #[cfg(not(feature = "std"))] + pub(crate) struct TestError(pub(crate) &'static str); impl Display for TestError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -91,12 +109,21 @@ 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"); diff --git a/src/eyreish/context.rs b/src/eyreish/context.rs index ee1fa08..1dbb543 100644 --- a/src/eyreish/context.rs +++ b/src/eyreish/context.rs @@ -1,8 +1,15 @@ +extern crate alloc; + use super::error::{ContextError, ErrorImpl}; use super::{Report, WrapErr}; use core::fmt::{self, Debug, Display, Write}; +use core::convert::Infallible; +#[cfg(feature = "std")] use std::error::Error as StdError; +#[cfg(not(feature = "std"))] +use crate::StdError as StdError; +use alloc::boxed::Box; use crate::{Diagnostic, LabeledSpan}; @@ -38,7 +45,7 @@ mod ext { } } -impl WrapErr for Option { +impl WrapErr for Option { fn wrap_err(self, msg: D) -> Result where D: Display + Send + Sync + 'static, diff --git a/src/eyreish/error.rs b/src/eyreish/error.rs index 706470e..238e46c 100644 --- a/src/eyreish/error.rs +++ b/src/eyreish/error.rs @@ -1,8 +1,14 @@ +extern crate alloc; + use core::any::TypeId; use core::fmt::{self, Debug, Display}; use core::mem::ManuallyDrop; use core::ptr::{self, NonNull}; +#[cfg(feature = "std")] use std::error::Error as StdError; +#[cfg(not(feature = "std"))] +use crate::StdError as StdError; +use alloc::boxed::Box; use super::ptr::{Mut, Own, Ref}; use super::Report; @@ -429,7 +435,7 @@ impl Report { /// Construct a [`Report`] directly from an error-like type pub fn from_err(err: E) -> Self where - E: std::error::Error + Send + Sync + 'static, + E: StdError + Send + Sync + 'static, { super::DiagnosticError(Box::new(err)).into() } @@ -816,8 +822,16 @@ impl AsRef for Report { } } +#[cfg(feature = "std")] impl std::borrow::Borrow for Report { fn borrow(&self) -> &(dyn Diagnostic + 'static) { self.as_ref() } } + +#[cfg(not(feature = "std"))] +impl core::borrow::Borrow for Report { + fn borrow(&self) -> &(dyn Diagnostic + 'static) { + self.as_ref() + } +} diff --git a/src/eyreish/into_diagnostic.rs b/src/eyreish/into_diagnostic.rs index 1f90c34..b739b24 100644 --- a/src/eyreish/into_diagnostic.rs +++ b/src/eyreish/into_diagnostic.rs @@ -1,14 +1,21 @@ -use std::{error::Error, fmt::Display}; +extern crate alloc; + +#[cfg(feature = "std")] +use std::error::Error; +#[cfg(not(feature = "std"))] +use crate::StdError as Error; +use core::fmt::Display; +use alloc::boxed::Box; 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); +pub(crate) struct DiagnosticError(pub(crate) Box); -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}") } @@ -38,20 +45,31 @@ pub trait IntoDiagnostic { fn into_diagnostic(self) -> Result; } +#[cfg(feature = "std")] impl IntoDiagnostic for Result { fn into_diagnostic(self) -> Result { self.map_err(|e| DiagnosticError(Box::new(e)).into()) } } +#[cfg(not(feature = "std"))] +impl IntoDiagnostic for Result { + fn into_diagnostic(self) -> Result { + self.map_err(|e| DiagnosticError(Box::new(e)).into()) + } +} + #[cfg(test)] mod tests { + #[cfg(feature = "std")] use std::io::{self, ErrorKind}; use super::*; + #[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"); diff --git a/src/eyreish/kind.rs b/src/eyreish/kind.rs index 6b0f5ec..e6dd978 100644 --- a/src/eyreish/kind.rs +++ b/src/eyreish/kind.rs @@ -45,11 +45,17 @@ // let error = $msg; // (&error).miette_kind().new(error) +#[cfg(not(feature = "std"))] +extern crate alloc; + use super::Report; use core::fmt::{Debug, Display}; use crate::Diagnostic; +#[cfg(not(feature = "std"))] +use alloc::boxed::Box; + pub struct Adhoc; pub trait AdhocKind: Sized { diff --git a/src/eyreish/mod.rs b/src/eyreish/mod.rs index 3f35103..8a4598c 100644 --- a/src/eyreish/mod.rs +++ b/src/eyreish/mod.rs @@ -4,10 +4,16 @@ clippy::new_ret_no_self, clippy::wrong_self_convention )] -use core::fmt::Display; +extern crate alloc; +use core::fmt::Display; +use alloc::boxed::Box; + +#[cfg(feature = "std")] use std::error::Error as StdError; -use std::sync::OnceLock; +#[cfg(not(feature = "std"))] +use crate::StdError as StdError; +use spin::Once; #[allow(unreachable_pub)] pub use into_diagnostic::*; @@ -61,7 +67,11 @@ unsafe impl Send for Report {} pub type ErrorHook = Box Box + Sync + Send + 'static>; -static HOOK: OnceLock = OnceLock::new(); +static HOOK: Once = Once::new(); + +fn default_hook() -> ErrorHook { + Box::new(get_default_printer) +} /// Error indicating that [`set_hook()`] was unable to install the provided /// [`ErrorHook`]. @@ -81,18 +91,23 @@ impl Diagnostic for InstallError {} Set the error hook. */ pub fn set_hook(hook: ErrorHook) -> Result<(), InstallError> { - HOOK.set(hook).map_err(|_| InstallError) + HOOK.call_once(|| hook); + Ok(()) } #[cfg_attr(track_caller, track_caller)] #[cfg_attr(not(track_caller), allow(unused_mut))] fn capture_handler(error: &(dyn Diagnostic + 'static)) -> Box { - let hook = HOOK.get_or_init(|| Box::new(get_default_printer)).as_ref(); + static DEFAULT: Once = Once::new(); + let hook = HOOK.get().unwrap_or_else(|| { + DEFAULT.call_once(|| default_hook()); + DEFAULT.get().unwrap() + }); #[cfg(track_caller)] { let mut handler = hook(error); - handler.track_caller(std::panic::Location::caller()); + handler.track_caller(core::panic::Location::caller()); handler } #[cfg(not(track_caller))] @@ -193,7 +208,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` diff --git a/src/eyreish/ptr.rs b/src/eyreish/ptr.rs index 40c9c7b..947b5bd 100644 --- a/src/eyreish/ptr.rs +++ b/src/eyreish/ptr.rs @@ -1,4 +1,8 @@ -use std::{marker::PhantomData, ptr::NonNull}; +extern crate alloc; + +use core::marker::PhantomData; +use core::ptr::NonNull; +use alloc::boxed::Box; #[repr(transparent)] /// A raw pointer that owns its pointee diff --git a/src/eyreish/wrapper.rs b/src/eyreish/wrapper.rs index bab7320..6c03cc0 100644 --- a/src/eyreish/wrapper.rs +++ b/src/eyreish/wrapper.rs @@ -1,6 +1,14 @@ +extern crate alloc; + use core::fmt::{self, Debug, Display}; +#[cfg(feature = "std")] use std::error::Error as StdError; +#[cfg(not(feature = "std"))] +use crate::StdError as StdError; +use alloc::boxed::Box; +use alloc::string::String; +use alloc::vec::Vec; use crate::{Diagnostic, LabeledSpan, Report, SourceCode}; @@ -107,16 +115,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 { diff --git a/src/handler.rs b/src/handler.rs index 5cd5a53..37e4826 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -8,7 +8,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)] diff --git a/src/handlers/debug.rs b/src/handlers/debug.rs index 629908b..1c77062 100644 --- a/src/handlers/debug.rs +++ b/src/handlers/debug.rs @@ -1,4 +1,7 @@ -use std::fmt; +extern crate alloc; + +use core::fmt; +use alloc::vec::Vec; 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)?; diff --git a/src/handlers/json.rs b/src/handlers/json.rs index e37064c..966e348 100644 --- a/src/handlers/json.rs +++ b/src/handlers/json.rs @@ -1,4 +1,7 @@ -use std::fmt::{self, Write}; +extern crate alloc; + +use core::fmt::{self, Write}; +use alloc::string::ToString; use crate::{ diagnostic_chain::DiagnosticChain, protocol::Diagnostic, ReportHandler, Severity, SourceCode, diff --git a/src/handlers/narratable.rs b/src/handlers/narratable.rs index 8dead98..86f23b3 100644 --- a/src/handlers/narratable.rs +++ b/src/handlers/narratable.rs @@ -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::string::String; +use alloc::vec::Vec; +use alloc::boxed::Box; /** [`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(); diff --git a/src/lib.rs b/src/lib.rs index 21ad61d..7c2fd56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![no_std] + #![deny(missing_docs, missing_debug_implementations, nonstandard_style)] #![warn(unreachable_pub, rust_2018_idioms)] #![allow(unexpected_cfgs)] @@ -815,6 +817,23 @@ //! 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; + +#[cfg(feature = "std")] +pub use std::error::Error as StdError; + +#[cfg(not(feature = "std"))] +/// Compatibility trait for error handling in no_std environments. +/// This trait provides a subset of `std::error::Error` functionality +/// suitable for no_std environments. +pub trait StdError: core::fmt::Debug + core::fmt::Display { + /// Returns the lower-level source of this error, if any. + fn source(&self) -> Option<&(dyn StdError + 'static)> { + None + } +} + #[cfg(feature = "derive")] pub use miette_derive::*; diff --git a/src/macro_helpers.rs b/src/macro_helpers.rs index 157f2b3..47a6e5f 100644 --- a/src/macro_helpers.rs +++ b/src/macro_helpers.rs @@ -51,6 +51,7 @@ impl ToLabeledSpan for ToLabelSpanWrapper { span } } +#[cfg(not(feature = "std"))] impl ToLabeledSpan for ToLabelSpanWrapper where T: Into, diff --git a/src/miette_diagnostic.rs b/src/miette_diagnostic.rs index 9863e88..07ed724 100644 --- a/src/miette_diagnostic.rs +++ b/src/miette_diagnostic.rs @@ -1,7 +1,14 @@ -use std::{ - error::Error, - fmt::{Debug, Display}, -}; +extern crate alloc; + +use core::fmt::{Debug, Display}; +#[cfg(feature = "std")] +use std::error::Error; +#[cfg(not(feature = "std"))] +use crate::StdError as Error; +use alloc::string::String; +use alloc::vec::{self, Vec}; +use alloc::format; +use alloc::boxed::Box; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -39,7 +46,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 +190,7 @@ impl MietteDiagnostic { /// assert_eq!(diag.labels, Some(vec![label])); /// ``` pub fn with_label(mut self, label: impl Into) -> Self { - self.labels = Some(vec![label.into()]); + self.labels = Some(Vec::from([label.into()])); self } diff --git a/src/named_source.rs b/src/named_source.rs index ea11cd2..415f088 100644 --- a/src/named_source.rs +++ b/src/named_source.rs @@ -10,8 +10,14 @@ pub struct NamedSource { language: Option, } -impl std::fmt::Debug for NamedSource { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +extern crate alloc; + +use alloc::string::String; +use alloc::string::ToString; +use alloc::boxed::Box; + +impl core::fmt::Debug for NamedSource { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("NamedSource") .field("name", &self.name) .field("source", &"") diff --git a/src/protocol.rs b/src/protocol.rs index 96ae9a3..10bb283 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -3,11 +3,15 @@ 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 core::fmt::{self, Display}; +#[cfg(feature = "std")] +use std::fs; +use core::panic::Location; +use core::ops; +use alloc::boxed::Box; +use alloc::string::String; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -17,7 +21,7 @@ use crate::{DiagnosticError, 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 +76,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 +94,7 @@ box_error_impls! { macro_rules! box_borrow_impls { ($($box_type:ty),*) => { $( - impl std::borrow::Borrow for $box_type { + impl core::borrow::Borrow for $box_type { fn borrow(&self) -> &(dyn Diagnostic + 'static) { self.as_ref() } @@ -152,7 +152,10 @@ impl From for Box { fn from(s: String) -> Self { struct StringError(String); + #[cfg(feature = "std")] impl std::error::Error for StringError {} + #[cfg(not(feature = "std"))] + impl crate::StdError for StringError {} impl Diagnostic for StringError {} impl Display for StringError { @@ -172,6 +175,7 @@ impl From for Box { } } +#[cfg(feature = "std")] impl From> for Box { fn from(s: Box) -> Self { Box::new(DiagnosticError(s)) @@ -594,8 +598,8 @@ impl From<(SourceOffset, usize)> for SourceSpan { } } -impl From> for SourceSpan { - fn from(range: std::ops::Range) -> Self { +impl From> for SourceSpan { + fn from(range: ops::Range) -> Self { Self { offset: range.start.into(), length: range.len(), @@ -603,12 +607,12 @@ impl From> for SourceSpan { } } -impl From> for SourceSpan { +impl From> 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) -> Self { + fn from(range: ops::RangeInclusive) -> Self { let (start, end) = range.clone().into_inner(); Self { offset: start.into(), @@ -715,6 +719,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(( @@ -723,6 +728,15 @@ impl SourceOffset { .map(|txt| Self::from_location(txt, loc.line() as usize, loc.column() as usize))?, )) } + + /// Returns both the filename that was given and the offset of the caller + /// as a [`SourceOffset`]. + /// + /// In no_std environments, this is not supported and will return an error. + #[cfg(not(feature = "std"))] + pub fn from_current_location() -> Result<(String, Self), MietteError> { + Err(MietteError::OutOfBounds) + } } impl From for SourceOffset { diff --git a/src/source_impls.rs b/src/source_impls.rs index 9c26b71..4fa60c3 100644 --- a/src/source_impls.rs +++ b/src/source_impls.rs @@ -1,7 +1,16 @@ /*! Default trait implementations for [`SourceCode`]. */ -use std::{borrow::Cow, collections::VecDeque, fmt::Debug, sync::Arc}; +extern crate alloc; + +use core::fmt::Debug; +use alloc::borrow::Cow; +use alloc::borrow::ToOwned; +use alloc::collections::VecDeque; +use alloc::sync::Arc; +use alloc::string::String; +use alloc::vec::Vec; +use alloc::boxed::Box; 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());