fix: address review comments

- Fixed compilation errors in no-std mode (TestError Debug derive, ToString imports)
- Addressed consistency issues: Option qualification, StdError naming, Borrow impl
- Fixed feature flag logic for supports_color function with proper priority ordering
- Added conditional compilation for std-dependent features in panic.rs, handler.rs, theme.rs
- Made syntect-highlighter feature explicitly require std
- Consolidated duplicate Borrow implementations using core::borrow::Borrow
This commit is contained in:
François Garillot 2025-11-15 16:09:22 -05:00
parent 18c217f0dc
commit 359941fdef
No known key found for this signature in database
GPG Key ID: E7645C6B883A1E9A
13 changed files with 98 additions and 43 deletions

View File

@ -65,7 +65,7 @@ fancy-no-backtrace = [
"dep:supports-unicode", "dep:supports-unicode",
] ]
fancy = ["fancy-no-backtrace", "dep:backtrace", "dep:backtrace-ext"] fancy = ["fancy-no-backtrace", "dep:backtrace", "dep:backtrace-ext"]
syntect-highlighter = ["fancy-no-backtrace", "dep:syntect"] syntect-highlighter = ["fancy-no-backtrace", "dep:syntect", "std"]
[workspace] [workspace]
members = ["miette-derive"] members = ["miette-derive"]

View File

@ -58,8 +58,8 @@ diagnostic error code: ruget::api::bad_json
### Features ### Features
- Generic [`Diagnostic`] protocol, compatible (and dependent on) - Generic [`Diagnostic`] protocol, compatible with `std::error::Error`.
[`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`]. - Unique error codes on every [`Diagnostic`].
- Custom links to get more details on error codes. - Custom links to get more details on error codes.
- Super handy derive macro for defining diagnostic metadata. - 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 $ 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 ### Example
```rust ```rust

View File

@ -5,12 +5,8 @@ fn main() {
println!("cargo:rustc-cfg=nightly") println!("cargo:rustc-cfg=nightly")
} }
// Configure track_caller based on Rust version // track_caller is stable since Rust 1.46 (2020), so no version check needed
if let Ok(version) = rustc_version::version() { println!("cargo:rustc-cfg=track_caller");
if version >= rustc_version::Version::new(1, 46, 0) {
println!("cargo:rustc-cfg=track_caller");
}
}
// Add check-cfg for conditional configurations // Add check-cfg for conditional configurations
println!("cargo:rustc-check-cfg=cfg(doc_cfg)"); println!("cargo:rustc-check-cfg=cfg(doc_cfg)");

View File

@ -56,13 +56,13 @@ impl Code {
let code = &code.as_ref()?.0; let code = &code.as_ref()?.0;
Some(match fields { Some(match fields {
syn::Fields::Named(_) => { syn::Fields::Named(_) => {
quote! { Self::#ident { .. } => Option::Some(alloc::boxed::Box::new(#code)), } quote! { Self::#ident { .. } => core::option::Option::Some(alloc::boxed::Box::new(#code)), }
} }
syn::Fields::Unnamed(_) => { syn::Fields::Unnamed(_) => {
quote! { Self::#ident(..) => Option::Some(alloc::boxed::Box::new(#code)), } quote! { Self::#ident(..) => core::option::Option::Some(alloc::boxed::Box::new(#code)), }
} }
syn::Fields::Unit => { syn::Fields::Unit => {
quote! { Self::#ident => Option::Some(alloc::boxed::Box::new(#code)), } quote! { Self::#ident => core::option::Option::Some(alloc::boxed::Box::new(#code)), }
} }
}) })
}, },
@ -72,8 +72,8 @@ impl Code {
pub(crate) fn gen_struct(&self) -> Option<TokenStream> { pub(crate) fn gen_struct(&self) -> Option<TokenStream> {
let code = &self.0; let code = &self.0;
Some(quote! { Some(quote! {
fn code(&self) -> Option<alloc::boxed::Box<dyn core::fmt::Display + '_>> { fn code(&self) -> core::option::Option<alloc::boxed::Box<dyn core::fmt::Display + '_>> {
Some(alloc::boxed::Box::new(#code)) core::option::Option::Some(alloc::boxed::Box::new(#code))
} }
}) })
} }

View File

@ -59,7 +59,7 @@ impl DiagnosticSource {
}; };
quote! { quote! {
Self::#ident #display_pat => { Self::#ident #display_pat => {
Some(alloc::borrow::Borrow::borrow(#rel)) core::option::Option::Some(alloc::borrow::Borrow::borrow(#rel))
} }
} }
}) })
@ -70,8 +70,8 @@ impl DiagnosticSource {
pub(crate) fn gen_struct(&self) -> Option<TokenStream> { pub(crate) fn gen_struct(&self) -> Option<TokenStream> {
let rel = &self.0; let rel = &self.0;
Some(quote! { Some(quote! {
fn diagnostic_source<'a>(&'a self) -> Option<&'a dyn miette::Diagnostic> { fn diagnostic_source<'a>(&'a self) -> core::option::Option<&'a dyn miette::Diagnostic> {
Some(alloc::borrow::Borrow::borrow(&self.#rel)) core::option::Option::Some(alloc::borrow::Borrow::borrow(&self.#rel))
} }
}) })
} }

View File

@ -93,6 +93,9 @@ impl Diagnostic for MietteError {
pub(crate) mod tests { pub(crate) mod tests {
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
use crate::StdError as Error; use crate::StdError as Error;
#[cfg(not(feature = "std"))]
use alloc::string::ToString;
#[cfg(feature = "std")]
use std::string::ToString; use std::string::ToString;
use super::*; use super::*;
@ -101,6 +104,7 @@ pub(crate) mod tests {
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub(crate) struct TestError(pub(crate) io::Error); pub(crate) struct TestError(pub(crate) io::Error);
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
#[derive(Debug)]
pub(crate) struct TestError(pub(crate) &'static str); pub(crate) struct TestError(pub(crate) &'static str);
impl Display for TestError { impl Display for TestError {

View File

@ -817,14 +817,6 @@ impl AsRef<dyn StdError> for Report {
} }
} }
#[cfg(feature = "std")]
impl std::borrow::Borrow<dyn Diagnostic> for Report {
fn borrow(&self) -> &(dyn Diagnostic + 'static) {
self.as_ref()
}
}
#[cfg(not(feature = "std"))]
impl core::borrow::Borrow<dyn Diagnostic> for Report { impl core::borrow::Borrow<dyn Diagnostic> for Report {
fn borrow(&self) -> &(dyn Diagnostic + 'static) { fn borrow(&self) -> &(dyn Diagnostic + 'static) {
self.as_ref() self.as_ref()

View File

@ -60,13 +60,12 @@ impl<T, E: Error + Send + Sync + 'static> IntoDiagnostic<T, E> for Result<T, E>
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::IntoDiagnostic;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::io::{self}; use std::io::{self};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::string::ToString; use std::string::ToString;
use super::*;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use crate::error::tests::TestError; use crate::error::tests::TestError;

View File

@ -357,7 +357,7 @@ impl MietteHandlerOpts {
// In no-std environment, assume graphics are available // In no-std environment, assume graphics are available
true true
} }
#[cfg(not(feature = "fancy-no-syscall"))] #[cfg(all(not(feature = "fancy-no-syscall"), feature = "std"))]
{ {
// In std environment, check NO_GRAPHICS env var // In std environment, check NO_GRAPHICS env var
if let Ok(env) = std::env::var("NO_GRAPHICS") { if let Ok(env) = std::env::var("NO_GRAPHICS") {
@ -366,6 +366,11 @@ impl MietteHandlerOpts {
true true
} }
} }
#[cfg(all(not(feature = "fancy-no-syscall"), not(feature = "std")))]
{
// In no-std environment without fancy-no-syscall, default to true
true
}
} }
} }
@ -487,8 +492,10 @@ mod syscall {
cfg_if! { cfg_if! {
if #[cfg(any(feature = "fancy-no-syscall", miri))] { if #[cfg(any(feature = "fancy-no-syscall", miri))] {
None None
} else { } else if #[cfg(feature = "fancy-no-backtrace")] {
terminal_size::terminal_size().map(|size| size.0 .0 as usize) terminal_size::terminal_size().map(|size| size.0 .0 as usize)
} else {
None
} }
} }
} }
@ -498,8 +505,10 @@ mod syscall {
cfg_if! { cfg_if! {
if #[cfg(feature = "fancy-no-syscall")] { if #[cfg(feature = "fancy-no-syscall")] {
false false
} else { } else if #[cfg(feature = "fancy-no-backtrace")] {
supports_hyperlinks::on(supports_hyperlinks::Stream::Stderr) supports_hyperlinks::on(supports_hyperlinks::Stream::Stderr)
} else {
false
} }
} }
} }
@ -507,13 +516,18 @@ mod syscall {
#[inline] #[inline]
pub(super) fn supports_color() -> bool { pub(super) fn supports_color() -> bool {
cfg_if! { cfg_if! {
if #[cfg(feature = "fancy-no-backtrace")] { if #[cfg(all(feature = "fancy", not(feature = "fancy-no-syscall")))] {
// Standard fancy mode with full std support
supports_color::on(supports_color::Stream::Stderr).is_some() supports_color::on(supports_color::Stream::Stderr).is_some()
} else if #[cfg(feature = "fancy-no-syscall")] { } else if #[cfg(all(feature = "fancy", feature = "fancy-no-backtrace"))] {
// In no-std environment without color support, default to no color support // Fancy mode without backtrace but with color support
supports_color::on(supports_color::Stream::Stderr).is_some()
} else if #[cfg(not(feature = "std"))] {
// No-std environment - no color support by default
false false
} else { } else {
true // Fallback to assuming color support // All other cases - no color support
false
} }
} }
} }
@ -537,8 +551,10 @@ mod syscall {
cfg_if! { cfg_if! {
if #[cfg(feature = "fancy-no-syscall")] { if #[cfg(feature = "fancy-no-syscall")] {
false false
} else { } else if #[cfg(feature = "fancy-no-backtrace")] {
supports_unicode::on(supports_unicode::Stream::Stderr) supports_unicode::on(supports_unicode::Stream::Stderr)
} else {
false
} }
} }
} }

View File

@ -76,7 +76,7 @@ impl Default for GraphicalTheme {
// In no-std environments, default to no-color mode // In no-std environments, default to no-color mode
Self::unicode_nocolor() Self::unicode_nocolor()
} }
#[cfg(not(feature = "fancy-no-syscall"))] #[cfg(all(not(feature = "fancy-no-syscall"), feature = "std"))]
{ {
match std::env::var("NO_COLOR") { match std::env::var("NO_COLOR") {
_ if !std::io::stdout().is_terminal() || !std::io::stderr().is_terminal() => { _ if !std::io::stdout().is_terminal() || !std::io::stderr().is_terminal() => {
@ -86,6 +86,11 @@ impl Default for GraphicalTheme {
_ => Self::unicode(), _ => Self::unicode(),
} }
} }
#[cfg(all(not(feature = "fancy-no-syscall"), not(feature = "std")))]
{
// In no-std environment, default to unicode theme
Self::unicode()
}
} }
} }

View File

@ -1,3 +1,4 @@
use core::str;
use std::path::Path; use std::path::Path;
extern crate alloc; extern crate alloc;

View File

@ -60,8 +60,8 @@
//! //!
//! ## Features //! ## Features
//! //!
//! - Generic [`Diagnostic`] protocol, compatible (and dependent on) //! - Generic [`Diagnostic`] protocol, compatible with `std::error::Error`.
//! [`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`]. //! - Unique error codes on every [`Diagnostic`].
//! - Custom links to get more details on error codes. //! - Custom links to get more details on error codes.
//! - Super handy derive macro for defining diagnostic metadata. //! - Super handy derive macro for defining diagnostic metadata.
@ -95,6 +95,19 @@
//! $ cargo add miette --features fancy //! $ 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 //! ## Example
//! //!
//! ```rust //! ```rust
@ -829,10 +842,6 @@
//! under the Apache License. Some code is taken from //! under the Apache License. Some code is taken from
//! [`ariadne`](https://github.com/zesterer/ariadne), which is MIT licensed. //! [`ariadne`](https://github.com/zesterer/ariadne), which is MIT licensed.
// For doctests that use Diagnostic derive macro
#[cfg(test)]
extern crate alloc;
#[cfg(feature = "std")] #[cfg(feature = "std")]
extern crate std; extern crate std;

View File

@ -1,4 +1,6 @@
#[cfg(feature = "std")]
use std::boxed::Box; use std::boxed::Box;
#[cfg(feature = "std")]
use std::{ use std::{
eprintln, eprintln,
error::Error, error::Error,
@ -7,11 +9,14 @@ use std::{
string::{String, ToString}, string::{String, ToString},
}; };
#[cfg(feature = "std")]
use backtrace::Backtrace; use backtrace::Backtrace;
#[cfg(feature = "std")]
use crate::{Context, Diagnostic, Result}; use crate::{Context, Diagnostic, Result};
/// Tells miette to render panics using its rendering engine. /// Makes miette show pretty error messages when your program crashes.
#[cfg(feature = "std")]
pub fn set_panic_hook() { pub fn set_panic_hook() {
std::panic::set_hook(Box::new(move |info| { std::panic::set_hook(Box::new(move |info| {
let mut message = "Something went wrong".to_string(); let mut message = "Something went wrong".to_string();
@ -33,9 +38,20 @@ pub fn set_panic_hook() {
})); }));
} }
/// Makes miette show pretty error messages when your program crashes.
///
/// On computers without the standard library, this function does nothing
/// because crash hooks need the standard library to work.
#[cfg(not(feature = "std"))]
pub fn set_panic_hook() {
// Does nothing on computers without the standard library
}
#[derive(Debug)] #[derive(Debug)]
#[cfg(feature = "std")]
struct Panic(String); struct Panic(String);
#[cfg(feature = "std")]
impl Display for Panic { impl Display for Panic {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let msg = &self.0; let msg = &self.0;
@ -44,8 +60,10 @@ impl Display for Panic {
} }
} }
#[cfg(feature = "std")]
impl Error for Panic {} impl Error for Panic {}
#[cfg(feature = "std")]
impl Diagnostic for Panic { impl Diagnostic for Panic {
fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> { fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
Some(Box::new( Some(Box::new(
@ -54,6 +72,7 @@ impl Diagnostic for Panic {
} }
} }
#[cfg(feature = "std")]
impl Panic { impl Panic {
fn backtrace() -> String { fn backtrace() -> String {
use std::fmt::Write; use std::fmt::Write;
@ -110,6 +129,7 @@ impl Panic {
} }
#[cfg(test)] #[cfg(test)]
#[cfg(feature = "std")]
mod tests { mod tests {
use std::{borrow::ToOwned, error::Error}; use std::{borrow::ToOwned, error::Error};