mirror of
https://github.com/dtolnay/thiserror.git
synced 2025-04-01 20:07:38 +03:00
Allow disabling std dependency on 1.81+
This commit is contained in:
parent
8277ec4a73
commit
d8ed5fbc2f
10 changed files with 146 additions and 9 deletions
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
@ -24,7 +24,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
rust: [nightly, beta, stable, 1.70.0]
|
||||
rust: [nightly, beta, stable, 1.81.0, 1.70.0]
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
@ -38,7 +38,9 @@ jobs:
|
|||
- name: Enable nightly-only tests
|
||||
run: echo RUSTFLAGS=${RUSTFLAGS}\ --cfg=thiserror_nightly_testing >> $GITHUB_ENV
|
||||
if: matrix.rust == 'nightly'
|
||||
- run: cargo test --all
|
||||
- run: cargo test --workspace --exclude thiserror_no_std_test
|
||||
- run: cargo test --manifest-path tests/no-std/Cargo.toml
|
||||
if: matrix.rust != '1.70.0'
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: matrix.rust == 'nightly' && always()
|
||||
with:
|
||||
|
|
18
Cargo.toml
18
Cargo.toml
|
@ -11,6 +11,22 @@ license = "MIT OR Apache-2.0"
|
|||
repository = "https://github.com/dtolnay/thiserror"
|
||||
rust-version = "1.61"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
|
||||
# Std feature enables support for formatting std::path::{Path, PathBuf}
|
||||
# conveniently in an error message.
|
||||
#
|
||||
# #[derive(Error, Debug)]
|
||||
# #[error("failed to create configuration file {path}")]
|
||||
# pub struct MyError {
|
||||
# pub path: PathBuf,
|
||||
# pub source: std::io::Error,
|
||||
# }
|
||||
#
|
||||
# Without std, this would need to be written #[error("... {}", path.display())].
|
||||
std = []
|
||||
|
||||
[dependencies]
|
||||
thiserror-impl = { version = "=1.0.68", path = "impl" }
|
||||
|
||||
|
@ -21,7 +37,7 @@ rustversion = "1.0.13"
|
|||
trybuild = { version = "1.0.81", features = ["diff"] }
|
||||
|
||||
[workspace]
|
||||
members = ["impl"]
|
||||
members = ["impl", "tests/no-std"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
|
9
build.rs
9
build.rs
|
@ -57,7 +57,14 @@ fn main() {
|
|||
println!("cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP");
|
||||
}
|
||||
|
||||
let rustc = match rustc_minor_version() {
|
||||
// core::error::Error stabilized in Rust 1.81
|
||||
// https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#coreerrorerror
|
||||
let rustc = rustc_minor_version();
|
||||
if cfg!(not(feature = "std")) && rustc.map_or(false, |rustc| rustc < 81) {
|
||||
println!("cargo:rustc-cfg=feature=\"std\"");
|
||||
}
|
||||
|
||||
let rustc = match rustc {
|
||||
Some(rustc) => rustc,
|
||||
None => return,
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// member access API. If the current toolchain is able to compile it, then
|
||||
// thiserror is able to provide backtrace support.
|
||||
|
||||
#![no_std]
|
||||
#![feature(error_generic_member_access)]
|
||||
|
||||
use core::error::{Error, Request};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use core::error::Error;
|
||||
use core::panic::UnwindSafe;
|
||||
use std::error::Error;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait AsDynError<'a>: Sealed {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use core::fmt::Display;
|
||||
#[cfg(feature = "std")]
|
||||
use std::path::{self, Path, PathBuf};
|
||||
|
||||
#[doc(hidden)]
|
||||
|
@ -21,6 +22,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'a> AsDisplay<'a> for Path {
|
||||
type Target = path::Display<'a>;
|
||||
|
||||
|
@ -30,6 +32,7 @@ impl<'a> AsDisplay<'a> for Path {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'a> AsDisplay<'a> for PathBuf {
|
||||
type Target = path::Display<'a>;
|
||||
|
||||
|
@ -42,5 +45,37 @@ impl<'a> AsDisplay<'a> for PathBuf {
|
|||
#[doc(hidden)]
|
||||
pub trait Sealed {}
|
||||
impl<T: Display> Sealed for &T {}
|
||||
#[cfg(feature = "std")]
|
||||
impl Sealed for Path {}
|
||||
#[cfg(feature = "std")]
|
||||
impl Sealed for PathBuf {}
|
||||
|
||||
// Add a synthetic second impl of AsDisplay to prevent the "single applicable
|
||||
// impl" rule from making too weird inference decision based on the single impl
|
||||
// for &T, which could lead to code that compiles with thiserror's std feature
|
||||
// off but breaks under feature unification when std is turned on by an
|
||||
// unrelated crate.
|
||||
#[cfg(not(feature = "std"))]
|
||||
mod placeholder {
|
||||
use super::{AsDisplay, Sealed};
|
||||
use core::fmt::{self, Display};
|
||||
|
||||
pub struct Placeholder;
|
||||
|
||||
impl<'a> AsDisplay<'a> for Placeholder {
|
||||
type Target = Self;
|
||||
|
||||
#[inline]
|
||||
fn as_display(&'a self) -> Self::Target {
|
||||
Placeholder
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Placeholder {
|
||||
fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Sealed for Placeholder {}
|
||||
}
|
||||
|
|
12
src/lib.rs
12
src/lib.rs
|
@ -258,6 +258,7 @@
|
|||
//!
|
||||
//! [`anyhow`]: https://github.com/dtolnay/anyhow
|
||||
|
||||
#![no_std]
|
||||
#![doc(html_root_url = "https://docs.rs/thiserror/1.0.68")]
|
||||
#![allow(
|
||||
clippy::module_name_repetitions,
|
||||
|
@ -270,6 +271,11 @@
|
|||
#[cfg(all(thiserror_nightly_testing, not(error_generic_member_access)))]
|
||||
compile_error!("Build script probe failed to compile.");
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std as core;
|
||||
|
||||
mod aserror;
|
||||
mod display;
|
||||
#[cfg(error_generic_member_access)]
|
||||
|
@ -287,9 +293,9 @@ pub mod __private {
|
|||
#[cfg(error_generic_member_access)]
|
||||
#[doc(hidden)]
|
||||
pub use crate::provide::ThiserrorProvide;
|
||||
#[cfg(not(thiserror_no_backtrace_type))]
|
||||
#[doc(hidden)]
|
||||
pub use core::error::Error;
|
||||
#[cfg(all(feature = "std", not(thiserror_no_backtrace_type)))]
|
||||
#[doc(hidden)]
|
||||
pub use std::backtrace::Backtrace;
|
||||
#[doc(hidden)]
|
||||
pub use std::error::Error;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::error::{Error, Request};
|
||||
use core::error::{Error, Request};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait ThiserrorProvide: Sealed {
|
||||
|
|
12
tests/no-std/Cargo.toml
Normal file
12
tests/no-std/Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "thiserror_no_std_test"
|
||||
version = "0.0.0"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
path = "test.rs"
|
||||
|
||||
[dependencies]
|
||||
thiserror = { path = "../..", default-features = false }
|
58
tests/no-std/test.rs
Normal file
58
tests/no-std/test.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
#![no_std]
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Error::E")]
|
||||
E(#[from] SourceError),
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[error("SourceError {field}")]
|
||||
pub struct SourceError {
|
||||
pub field: i32,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{Error, SourceError};
|
||||
use core::error::Error as _;
|
||||
use core::fmt::{self, Write};
|
||||
use core::mem;
|
||||
|
||||
struct Buf<'a>(&'a mut [u8]);
|
||||
|
||||
impl Write for Buf<'_> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
if s.len() <= self.0.len() {
|
||||
let (out, rest) = mem::take(&mut self.0).split_at_mut(s.len());
|
||||
out.copy_from_slice(s.as_bytes());
|
||||
self.0 = rest;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(fmt::Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let source = SourceError { field: -1 };
|
||||
let error = Error::from(source);
|
||||
|
||||
let source = error
|
||||
.source()
|
||||
.unwrap()
|
||||
.downcast_ref::<SourceError>()
|
||||
.unwrap();
|
||||
|
||||
let mut msg = [b'~'; 17];
|
||||
write!(Buf(&mut msg), "{error}").unwrap();
|
||||
assert_eq!(msg, *b"Error::E~~~~~~~~~");
|
||||
|
||||
let mut msg = [b'~'; 17];
|
||||
write!(Buf(&mut msg), "{source}").unwrap();
|
||||
assert_eq!(msg, *b"SourceError -1~~~");
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue