Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"rust-analyzer.cargo.features": "all"
"rust-analyzer.cargo.features": "all",
}
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@ license = { workspace = true }

[dependencies]
thiserror = "2"
thiserror-ext-derive = { version = "=0.3.0", path = "derive" }
thiserror-ext-derive = { version = "=0.3.1-alpha.1", path = "derive" }

[dev-dependencies]
anyhow = "1"
expect-test = "1"
sealed_test = "1"

[features]
backtrace = ["thiserror-ext-derive/backtrace"]
provide = ["thiserror-ext-derive/provide"]
backtrace = ["provide"]

[workspace]
members = ["derive"]
package.version = "0.3.0"
package.version = "0.3.1-alpha.1"
package.edition = "2021"
package.authors = ["Bugen Zhao <i@bugenzhao.com>"]
package.repository = "https://github.com/risingwavelabs/thiserror-ext"
Expand Down
3 changes: 2 additions & 1 deletion derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ license = { workspace = true }
proc-macro = true

[features]
backtrace = []
backtrace = ["provide"]
provide = []

[dependencies]
either = "1"
Expand Down
60 changes: 49 additions & 11 deletions derive/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ fn resolve_args_for_macro(fields: &[Field<'_>]) -> MacroArgs {
struct DeriveMeta {
impl_type: Ident,
nt_backtrace: bool,
nt_extra_provide: Option<TokenStream>,
macro_mangle: bool,
macro_path: Option<TokenStream>,
macro_vis: Option<Visibility>,
Expand All @@ -140,6 +141,7 @@ struct DeriveMeta {
fn resolve_meta(input: &DeriveInput) -> Result<DeriveMeta> {
let mut new_type = None;
let mut nt_backtrace = false;
let mut nt_extra_provide = None;
let mut macro_mangle = false;
let mut macro_path = None;
let mut macro_vis = None;
Expand All @@ -153,12 +155,22 @@ fn resolve_meta(input: &DeriveInput) -> Result<DeriveMeta> {
let value = meta.value()?;
new_type = Some(value.parse()?);
} else if meta.path.is_ident("backtrace") {
if cfg!(feature = "backtrace") {
if cfg!(feature = "provide") {
nt_backtrace = true;
} else {
return Err(Error::new_spanned(
meta.path,
"enable the `backtrace` feature to use `backtrace` attribute",
"enable the `backtrace` or `provide` feature to use `backtrace` attribute",
));
}
} else if meta.path.is_ident("extra_provide") {
if cfg!(feature = "provide") {
let value = meta.value()?;
nt_extra_provide = Some(value.parse()?);
} else {
return Err(Error::new_spanned(
meta.path,
"enable the `backtrace` or `provide` feature to use `extra_provide` attribute",
));
}
} else {
Expand Down Expand Up @@ -211,6 +223,7 @@ fn resolve_meta(input: &DeriveInput) -> Result<DeriveMeta> {
Ok(DeriveMeta {
impl_type,
nt_backtrace,
nt_extra_provide,
macro_mangle,
macro_path,
macro_vis,
Expand Down Expand Up @@ -250,6 +263,7 @@ pub fn derive_new_type(input: &DeriveInput, ty: DeriveNewType) -> Result<TokenSt
let DeriveMeta {
impl_type,
nt_backtrace: backtrace,
nt_extra_provide: extra_provide,
..
} = resolve_meta(input)?;

Expand Down Expand Up @@ -281,11 +295,6 @@ pub fn derive_new_type(input: &DeriveInput, ty: DeriveNewType) -> Result<TokenSt
DeriveNewType::Box => quote!(),
DeriveNewType::Arc => quote!(Clone),
};
let backtrace_attr = if cfg!(feature = "backtrace") {
quote!(#[backtrace])
} else {
quote!()
};

let into_inner = match ty {
DeriveNewType::Box => quote!(
Expand All @@ -297,13 +306,28 @@ pub fn derive_new_type(input: &DeriveInput, ty: DeriveNewType) -> Result<TokenSt
DeriveNewType::Arc => quote!(),
};

let provide_fn = if backtrace || extra_provide.is_some() {
let extra_call = if let Some(extra_fn) = &extra_provide {
quote!(#extra_fn(self, request);)
} else {
quote!()
};

quote!(
fn provide<'a>(&'a self, request: &mut std::error::Request<'a>) {
self.0.provide(request);
#extra_call
}
)
.into()
} else {
None
};

let generated = quote!(
#[doc = #doc]
#[derive(thiserror_ext::__private::thiserror::Error, #extra_derive)]
#[error(transparent)]
#[derive(#extra_derive)]
#vis struct #impl_type(
#[from]
#backtrace_attr
thiserror_ext::__private::#new_type<
#input_type,
#backtrace_type_param,
Expand All @@ -320,6 +344,20 @@ pub fn derive_new_type(input: &DeriveInput, ty: DeriveNewType) -> Result<TokenSt
}
}

impl std::error::Error for #impl_type {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.0.source()
}

#provide_fn
}

impl std::fmt::Display for #impl_type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}

impl std::fmt::Debug for #impl_type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(&self.0, f)
Expand Down
2 changes: 1 addition & 1 deletion examples/context.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! This example demonstrates how to achieve the similar functionality as
//! [`anyhow::Context`] with `thiserror_ext`, in a type-safer manner.

#![cfg_attr(feature = "backtrace", feature(error_generic_member_access))]
#![cfg_attr(feature = "provide", feature(error_generic_member_access))]

use thiserror::Error;
use thiserror_ext::{AsReport, Box, ContextInto, Macro};
Expand Down
8 changes: 4 additions & 4 deletions src/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pub trait WithBacktrace {
/// Capture backtrace based on whether the error already has one.
fn capture(inner: &dyn std::error::Error) -> Self;

#[cfg(feature = "backtrace")]
#[cfg(feature = "provide")]
/// Provide the backtrace, if any.
fn provide<'a>(&'a self, request: &mut std::error::Request<'a>);
}
Expand All @@ -17,11 +17,11 @@ impl WithBacktrace for NoExtraBacktrace {
Self
}

#[cfg(feature = "backtrace")]
#[cfg(feature = "provide")]
fn provide<'a>(&'a self, _request: &mut std::error::Request<'a>) {}
}

#[cfg(feature = "backtrace")]
#[cfg(feature = "provide")]
mod maybe {
use super::WithBacktrace;
use std::backtrace::Backtrace;
Expand All @@ -47,5 +47,5 @@ mod maybe {
}
}

#[cfg(feature = "backtrace")]
#[cfg(feature = "provide")]
pub use maybe::MaybeBacktrace;
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
//! wrap an `enum` error type into a new type, reducing the size to improve
//! performance, and automatically capturing backtraces if needed.

#![cfg_attr(feature = "backtrace", feature(error_generic_member_access))]
#![cfg_attr(feature = "provide", feature(error_generic_member_access))]

mod as_dyn;
mod backtrace;
Expand All @@ -30,7 +30,7 @@ pub use thiserror_ext_derive::*;

#[doc(hidden)]
pub mod __private {
#[cfg(feature = "backtrace")]
#[cfg(feature = "provide")]
pub use crate::backtrace::MaybeBacktrace;
pub use crate::backtrace::NoExtraBacktrace;
pub use crate::ptr::{ErrorArc, ErrorBox};
Expand Down
4 changes: 2 additions & 2 deletions src/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ macro_rules! impl_methods {
}

impl<T, B> $ty<T, B> {
#[cfg_attr(not(feature = "backtrace"), allow(dead_code))]
#[cfg_attr(not(feature = "provide"), allow(dead_code))]
fn backtrace(&self) -> &B {
&self.0.as_ref().1
}
Expand Down Expand Up @@ -79,7 +79,7 @@ macro_rules! impl_methods {
}

// https://github.com/rust-lang/rust/issues/117432
#[cfg(feature = "backtrace")]
#[cfg(feature = "provide")]
fn provide<'a>(&'a self, request: &mut std::error::Request<'a>) {
self.backtrace().provide(request);
T::provide(self.inner(), request);
Expand Down
2 changes: 1 addition & 1 deletion src/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ impl fmt::Debug for Report<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.cleaned_error_trace(f, f.alternate())?;

#[cfg(feature = "backtrace")]
#[cfg(feature = "provide")]
{
use std::backtrace::{Backtrace, BacktraceStatus};

Expand Down
2 changes: 1 addition & 1 deletion tests/arc_new_type.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(feature = "backtrace", feature(error_generic_member_access))]
#![cfg_attr(feature = "provide", feature(error_generic_member_access))]

use std::{error::Error, num::ParseIntError};

Expand Down
2 changes: 1 addition & 1 deletion tests/backtrace.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(feature = "backtrace")]
#![cfg(feature = "provide")]
#![feature(error_generic_member_access)]

use std::backtrace::Backtrace;
Expand Down
6 changes: 3 additions & 3 deletions tests/basic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![cfg_attr(feature = "backtrace", feature(error_generic_member_access))]
#![cfg_attr(feature = "provide", feature(error_generic_member_access))]

#[cfg(feature = "backtrace")]
#[cfg(feature = "provide")]
use std::backtrace::Backtrace;
use thiserror::*;
use thiserror_ext::*;
Expand Down Expand Up @@ -41,7 +41,7 @@ impl MyError {
}
}

#[cfg(feature = "backtrace")]
#[cfg(feature = "provide")]
#[derive(Error, Debug, Construct, ContextInto, Box)]
#[thiserror_ext(newtype(name = MyErrorBacktrace))]
pub enum MyErrorBacktraceInner {
Expand Down
2 changes: 1 addition & 1 deletion tests/context_into.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! This example demonstrates how to achieve the similar functionality as
//! [`anyhow::Context`] with `thiserror_ext`, in a type-safer manner.

#![cfg_attr(feature = "backtrace", feature(error_generic_member_access))]
#![cfg_attr(feature = "provide", feature(error_generic_member_access))]

use expect_test::expect;
use thiserror::Error;
Expand Down
41 changes: 41 additions & 0 deletions tests/extra_provide.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#![cfg(feature = "provide")]
#![feature(error_generic_member_access)]

use std::error::Error;

use thiserror::*;
use thiserror_ext::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct ErrorCode(i32);

#[derive(Error, Debug, Arc, Construct)]
#[thiserror_ext(newtype(name = TestError, extra_provide = Self::my_extra_provide))]
enum TestErrorInner {
#[error("custom error")]
Custom(ErrorCode),
#[error("parse error")]
ParseError,
}

impl TestError {
fn my_extra_provide(&self, request: &mut std::error::Request<'_>) {
match self.inner() {
TestErrorInner::Custom(error_code) => request.provide_value(*error_code),
TestErrorInner::ParseError => request.provide_value(ErrorCode(42)),
};
}
}

fn request_error_code(error: &dyn Error) -> ErrorCode {
std::error::request_value(error).unwrap()
}

#[test]
fn test_extra_provide() {
let error_1 = TestError::custom(ErrorCode(114514));
let error_2 = TestError::parse_error();

assert_eq!(request_error_code(&error_1), ErrorCode(114514));
assert_eq!(request_error_code(&error_2), ErrorCode(42));
}
2 changes: 1 addition & 1 deletion tests/macro.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(feature = "backtrace", feature(error_generic_member_access))]
#![cfg_attr(feature = "provide", feature(error_generic_member_access))]

pub mod inner {
use thiserror::Error;
Expand Down
2 changes: 1 addition & 1 deletion tests/macro_anyhow.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Demonstrate that we can emulate a lightweight version of `anyhow` with `thiserror_ext`.

#![cfg_attr(feature = "backtrace", feature(error_generic_member_access))]
#![cfg_attr(feature = "provide", feature(error_generic_member_access))]

use thiserror::Error;
use thiserror_ext::Box;
Expand Down
2 changes: 1 addition & 1 deletion tests/report.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(feature = "backtrace")]
#![cfg(feature = "provide")]
#![feature(error_generic_member_access)]

use expect_test::expect;
Expand Down
2 changes: 1 addition & 1 deletion tests/report_debug.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(feature = "backtrace", feature(error_generic_member_access))]
#![cfg_attr(feature = "provide", feature(error_generic_member_access))]

use thiserror::Error;
use thiserror_ext::{Box, ReportDebug};
Expand Down
2 changes: 1 addition & 1 deletion tests/v2.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(feature = "backtrace", feature(error_generic_member_access))]
#![cfg_attr(feature = "provide", feature(error_generic_member_access))]
#![allow(dead_code)]

use thiserror::Error;
Expand Down