Skip to content

Commit 1d599bd

Browse files
committed
Pass through format args directly to support named arguments etc
1 parent 66ec060 commit 1d599bd

File tree

5 files changed

+20
-24
lines changed

5 files changed

+20
-24
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ autotests = false
1212

1313
[dependencies]
1414
quote = "1.0.3"
15+
proc-macro2 = "1.0.9"
1516

1617
[dependencies.syn]
1718
features = ["full", "parsing"]

src/lib.rs

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,17 @@ extern crate proc_macro;
22

33
use proc_macro::TokenStream;
44
use quote::quote;
5-
use syn::parse::{Parse, ParseStream};
6-
use syn::punctuated::Punctuated;
7-
use syn::token::Comma;
85

96
#[proc_macro_attribute]
107
pub fn error_context(args: TokenStream, input: TokenStream) -> TokenStream {
11-
let Args { fmt, args } = syn::parse_macro_input!(args as Args);
8+
let args: proc_macro2::TokenStream = args.into();
129
let mut input = syn::parse_macro_input!(input as syn::ItemFn);
1310

1411
let body = &input.block;
1512
let return_ty = &input.sig.output;
1613
input.block = syn::parse_quote!({
17-
(|| #return_ty #body)().map_err(|err| err.context(format!(#fmt, #args)).into())
14+
(|| #return_ty #body)().map_err(|err| err.context(format!(#args)).into())
1815
});
1916

2017
quote!(#input).into()
2118
}
22-
23-
struct Args {
24-
fmt: syn::LitStr,
25-
args: Punctuated<syn::Expr, Comma>,
26-
}
27-
28-
impl Parse for Args {
29-
fn parse(input: ParseStream) -> syn::Result<Self> {
30-
let fmt = input.parse()?;
31-
let args = if let Some(_) = input.parse::<Option<Comma>>()? {
32-
Punctuated::parse_separated_nonempty(input)?
33-
} else {
34-
Punctuated::new()
35-
};
36-
37-
Ok(Args { fmt, args })
38-
}
39-
}

tests/fmt_named_arg.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use fn_error_context::error_context;
2+
3+
#[error_context("context {arg}", arg = arg)]
4+
fn do_stuff(arg: u32) -> anyhow::Result<()> {
5+
anyhow::bail!("error {}", arg)
6+
}
7+
8+
fn main() {
9+
assert_eq!(
10+
format!("{:#}", do_stuff(1).unwrap_err()),
11+
"context 1: error 1"
12+
);
13+
}

tests/missing_fmt.stderr

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
error: unexpected end of input, expected literal
1+
error: requires at least a format string argument
22
--> $DIR/missing_fmt.rs:3:1
33
|
44
3 | #[error_context]
55
| ^^^^^^^^^^^^^^^^
6+
|
7+
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

tests/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ fn tests() {
1414
tests.pass("tests/as_ref.rs");
1515
tests.compile_fail("tests/fmt_missing_arg.rs");
1616
tests.compile_fail("tests/fmt_unused_arg.rs");
17+
tests.pass("tests/fmt_named_arg.rs");
1718
}

0 commit comments

Comments
 (0)