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",
]
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]
members = ["miette-derive"]

View File

@ -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

View File

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

View File

@ -56,13 +56,13 @@ impl Code {
let code = &code.as_ref()?.0;
Some(match fields {
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(_) => {
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 => {
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> {
let code = &self.0;
Some(quote! {
fn code(&self) -> Option<alloc::boxed::Box<dyn core::fmt::Display + '_>> {
Some(alloc::boxed::Box::new(#code))
fn code(&self) -> core::option::Option<alloc::boxed::Box<dyn core::fmt::Display + '_>> {
core::option::Option::Some(alloc::boxed::Box::new(#code))
}
})
}

View File

@ -59,7 +59,7 @@ impl DiagnosticSource {
};
quote! {
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> {
let rel = &self.0;
Some(quote! {
fn diagnostic_source<'a>(&'a self) -> Option<&'a dyn miette::Diagnostic> {
Some(alloc::borrow::Borrow::borrow(&self.#rel))
fn diagnostic_source<'a>(&'a self) -> core::option::Option<&'a dyn miette::Diagnostic> {
core::option::Option::Some(alloc::borrow::Borrow::borrow(&self.#rel))
}
})
}

View File

@ -93,6 +93,9 @@ impl Diagnostic for MietteError {
pub(crate) mod tests {
#[cfg(not(feature = "std"))]
use crate::StdError as Error;
#[cfg(not(feature = "std"))]
use alloc::string::ToString;
#[cfg(feature = "std")]
use std::string::ToString;
use super::*;
@ -101,6 +104,7 @@ pub(crate) mod tests {
#[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 {

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 {
fn borrow(&self) -> &(dyn Diagnostic + 'static) {
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)]
mod tests {
use super::IntoDiagnostic;
#[cfg(feature = "std")]
use std::io::{self};
#[cfg(feature = "std")]
use std::string::ToString;
use super::*;
#[cfg(feature = "std")]
use crate::error::tests::TestError;

View File

@ -357,7 +357,7 @@ impl MietteHandlerOpts {
// In no-std environment, assume graphics are available
true
}
#[cfg(not(feature = "fancy-no-syscall"))]
#[cfg(all(not(feature = "fancy-no-syscall"), feature = "std"))]
{
// In std environment, check NO_GRAPHICS env var
if let Ok(env) = std::env::var("NO_GRAPHICS") {
@ -366,6 +366,11 @@ impl MietteHandlerOpts {
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! {
if #[cfg(any(feature = "fancy-no-syscall", miri))] {
None
} else {
} else if #[cfg(feature = "fancy-no-backtrace")] {
terminal_size::terminal_size().map(|size| size.0 .0 as usize)
} else {
None
}
}
}
@ -498,8 +505,10 @@ mod syscall {
cfg_if! {
if #[cfg(feature = "fancy-no-syscall")] {
false
} else {
} else if #[cfg(feature = "fancy-no-backtrace")] {
supports_hyperlinks::on(supports_hyperlinks::Stream::Stderr)
} else {
false
}
}
}
@ -507,13 +516,18 @@ mod syscall {
#[inline]
pub(super) fn supports_color() -> bool {
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()
} else if #[cfg(feature = "fancy-no-syscall")] {
// In no-std environment without color support, default to no color support
} else if #[cfg(all(feature = "fancy", feature = "fancy-no-backtrace"))] {
// 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
} else {
true // Fallback to assuming color support
// All other cases - no color support
false
}
}
}
@ -537,8 +551,10 @@ mod syscall {
cfg_if! {
if #[cfg(feature = "fancy-no-syscall")] {
false
} else {
} else if #[cfg(feature = "fancy-no-backtrace")] {
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
Self::unicode_nocolor()
}
#[cfg(not(feature = "fancy-no-syscall"))]
#[cfg(all(not(feature = "fancy-no-syscall"), feature = "std"))]
{
match std::env::var("NO_COLOR") {
_ if !std::io::stdout().is_terminal() || !std::io::stderr().is_terminal() => {
@ -86,6 +86,11 @@ impl Default for GraphicalTheme {
_ => 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;
extern crate alloc;

View File

@ -60,8 +60,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.
@ -95,6 +95,19 @@
//! $ 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
@ -829,10 +842,6 @@
//! under the Apache License. Some code is taken from
//! [`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")]
extern crate std;

View File

@ -1,4 +1,6 @@
#[cfg(feature = "std")]
use std::boxed::Box;
#[cfg(feature = "std")]
use std::{
eprintln,
error::Error,
@ -7,11 +9,14 @@ use std::{
string::{String, ToString},
};
#[cfg(feature = "std")]
use backtrace::Backtrace;
#[cfg(feature = "std")]
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() {
std::panic::set_hook(Box::new(move |info| {
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)]
#[cfg(feature = "std")]
struct Panic(String);
#[cfg(feature = "std")]
impl Display for Panic {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let msg = &self.0;
@ -44,8 +60,10 @@ impl Display for Panic {
}
}
#[cfg(feature = "std")]
impl Error for Panic {}
#[cfg(feature = "std")]
impl Diagnostic for Panic {
fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
Some(Box::new(
@ -54,6 +72,7 @@ impl Diagnostic for Panic {
}
}
#[cfg(feature = "std")]
impl Panic {
fn backtrace() -> String {
use std::fmt::Write;
@ -110,6 +129,7 @@ impl Panic {
}
#[cfg(test)]
#[cfg(feature = "std")]
mod tests {
use std::{borrow::ToOwned, error::Error};