Skip to content

Commit d8c2d94

Browse files
Allow custom formatting (#37)
* Initial suppport for entering and exiting custom formatting Argument parsing done * Added example/test for custom formatting * Custom formatting now works, just needs examples, and better errors * Seperated the code for parsing custom formating * the parser for custom formatting gives back more reasonable errors Also fixed bug in parser which lead to non interpolated things being interpolated * custom formatting also for return values use {r} to interpolate return values the parser is getting a drop messy * added some documentation for custom formatting * more clean up from implementing custom formatting * made the logic for format_exit a little more simple * added error for when pretty and custom formatting are used together * changed custom formatting interpolation custom formatting interpolation now follows (mostly) the same rules as `fomat!` custom formatting interpolation now report (mostly) the same errors as `format!` fixed some copy pasted error reporting * Apply suggestions from code review --------- Co-authored-by: Gulshan Singh <[email protected]>
1 parent f890339 commit d8c2d94

File tree

4 files changed

+296
-33
lines changed

4 files changed

+296
-33
lines changed

examples/example_custom_format.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use trace::trace;
2+
3+
trace::init_depth_var!();
4+
5+
fn main() {
6+
foo(5, 4);
7+
}
8+
9+
#[trace(format_enter = "{y} and {z} {{7}}", format_exit = "{r} * {r}")]
10+
fn foo(z: u32, y: u32) -> u32 {
11+
z
12+
}
13+
14+
#[cfg(test)]
15+
#[macro_use]
16+
mod trace_test;
17+
18+
#[cfg(test)]
19+
trace_test!(test_custom_format, main());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[+] Entering foo(4 and 5 {7})
2+
[-] Exiting foo = 5 * 5

src/args.rs

+81-20
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use syn::{self, spanned::Spanned};
55
pub(crate) struct Args {
66
pub(crate) prefix_enter: String,
77
pub(crate) prefix_exit: String,
8+
pub(crate) format_enter: Option<String>,
9+
pub(crate) format_exit: Option<String>,
810
pub(crate) filter: Filter,
911
pub(crate) pause: bool,
1012
pub(crate) pretty: bool,
@@ -23,6 +25,17 @@ const DEFAULT_PAUSE: bool = false;
2325
const DEFAULT_PRETTY: bool = false;
2426
const DEFAULT_LOGGING: bool = false;
2527

28+
macro_rules! try_extract_str {
29+
($lit:expr, $meta:expr, $arg_ty:ident) => {{
30+
match *$lit {
31+
syn::Lit::Str(ref lit_str) => Ok(Arg::$arg_ty($meta.span(), lit_str.value())),
32+
_ => Err(vec![syn::Error::new_spanned(
33+
$lit,
34+
format!("`{}` must have a string value", stringify!($arg_ty)),
35+
)]),
36+
}
37+
}};
38+
}
2639
impl Args {
2740
pub(crate) fn from_raw_args(raw_args: syn::AttributeArgs) -> Result<Self, Vec<syn::Error>> {
2841
// Different types of arguments accepted by `#[trace]`;
@@ -35,6 +48,8 @@ impl Args {
3548
Pause(proc_macro2::Span, bool),
3649
Pretty(proc_macro2::Span, bool),
3750
Logging(proc_macro2::Span, bool),
51+
FormatEnter(proc_macro2::Span, String),
52+
FormatExit(proc_macro2::Span, String),
3853
}
3954

4055
// Parse arguments
@@ -43,6 +58,8 @@ impl Args {
4358
enum ArgName {
4459
PrefixEnter,
4560
PrefixExit,
61+
FormatEnter,
62+
FormatExit,
4663
Enable,
4764
Disable,
4865
Pause,
@@ -54,6 +71,8 @@ impl Args {
5471
let arg_name = match ident.to_string().as_str() {
5572
"prefix_enter" => ArgName::PrefixEnter,
5673
"prefix_exit" => ArgName::PrefixExit,
74+
"format_enter" => ArgName::FormatEnter,
75+
"format_exit" => ArgName::FormatExit,
5776
"enable" => ArgName::Enable,
5877
"disable" => ArgName::Disable,
5978
"pause" => ArgName::Pause,
@@ -79,6 +98,18 @@ impl Args {
7998
"`prefix_exit` requires a string value",
8099
)]
81100
};
101+
let format_enter_type_error = || {
102+
vec![syn::Error::new_spanned(
103+
ident.clone(),
104+
"`format_enter` requires a string value",
105+
)]
106+
};
107+
let format_exit_type_error = || {
108+
vec![syn::Error::new_spanned(
109+
ident.clone(),
110+
"`format_exit` requires a string value",
111+
)]
112+
};
82113
let enable_type_error = || {
83114
vec![syn::Error::new_spanned(
84115
ident.clone(),
@@ -115,11 +146,12 @@ impl Args {
115146
ArgName::Pause => Ok(Arg::Pause(meta.span(), true)),
116147
ArgName::Pretty => Ok(Arg::Pretty(meta.span(), true)),
117148
ArgName::Logging => Ok(Arg::Logging(meta.span(), true)),
118-
119149
ArgName::PrefixEnter => Err(prefix_enter_type_error()),
120150
ArgName::PrefixExit => Err(prefix_exit_type_error()),
121151
ArgName::Enable => Err(enable_type_error()),
122152
ArgName::Disable => Err(disable_type_error()),
153+
ArgName::FormatEnter => Err(format_enter_type_error()),
154+
ArgName::FormatExit => Err(format_exit_type_error()),
123155
},
124156
syn::Meta::List(syn::MetaList { ref nested, .. }) => match arg_name {
125157
ArgName::Enable => {
@@ -172,27 +204,14 @@ impl Args {
172204
ArgName::Pause => Err(pause_type_error()),
173205
ArgName::Pretty => Err(pretty_type_error()),
174206
ArgName::Logging => Err(logging_type_error()),
207+
ArgName::FormatEnter => Err(format_enter_type_error()),
208+
ArgName::FormatExit => Err(format_exit_type_error()),
175209
},
176210
syn::Meta::NameValue(syn::MetaNameValue { ref lit, .. }) => match arg_name {
177-
ArgName::PrefixEnter => match *lit {
178-
syn::Lit::Str(ref lit_str) => {
179-
Ok(Arg::PrefixEnter(meta.span(), lit_str.value()))
180-
}
181-
_ => Err(vec![syn::Error::new_spanned(
182-
lit,
183-
"`prefix_enter` must have a string value",
184-
)]),
185-
},
186-
ArgName::PrefixExit => match *lit {
187-
syn::Lit::Str(ref lit_str) => {
188-
Ok(Arg::PrefixExit(meta.span(), lit_str.value()))
189-
}
190-
_ => Err(vec![syn::Error::new_spanned(
191-
lit,
192-
"`prefix_exit` must have a string value",
193-
)]),
194-
},
195-
211+
ArgName::PrefixEnter => try_extract_str!(lit, meta, PrefixEnter),
212+
ArgName::PrefixExit => try_extract_str!(lit, meta, PrefixExit),
213+
ArgName::FormatEnter => try_extract_str!(lit, meta, FormatEnter),
214+
ArgName::FormatExit => try_extract_str!(lit, meta, FormatExit),
196215
ArgName::Enable => Err(enable_type_error()),
197216
ArgName::Disable => Err(disable_type_error()),
198217
ArgName::Pause => Err(pause_type_error()),
@@ -209,6 +228,8 @@ impl Args {
209228

210229
let mut prefix_enter_args = vec![];
211230
let mut prefix_exit_args = vec![];
231+
let mut format_enter_args = vec![];
232+
let mut format_exit_args = vec![];
212233
let mut enable_args = vec![];
213234
let mut disable_args = vec![];
214235
let mut pause_args = vec![];
@@ -227,6 +248,8 @@ impl Args {
227248
Arg::Pause(span, b) => pause_args.push((span, b)),
228249
Arg::Pretty(span, b) => pretty_args.push((span, b)),
229250
Arg::Logging(span, b) => logging_args.push((span, b)),
251+
Arg::FormatEnter(span, s) => format_enter_args.push((span, s)),
252+
Arg::FormatExit(span, s) => format_exit_args.push((span, s)),
230253
},
231254
Err(es) => errors.extend(es),
232255
}
@@ -247,6 +270,20 @@ impl Args {
247270
.map(|(span, _)| syn::Error::new(*span, "duplicate `prefix_exit`")),
248271
);
249272
}
273+
if format_enter_args.len() >= 2 {
274+
errors.extend(
275+
format_enter_args
276+
.iter()
277+
.map(|(span, _)| syn::Error::new(*span, "duplicate `format_enter`")),
278+
);
279+
}
280+
if format_exit_args.len() >= 2 {
281+
errors.extend(
282+
format_exit_args
283+
.iter()
284+
.map(|(span, _)| syn::Error::new(*span, "duplicate `format_exit`")),
285+
);
286+
}
250287
if enable_args.len() >= 2 {
251288
errors.extend(
252289
enable_args
@@ -294,6 +331,26 @@ impl Args {
294331
"cannot have both `enable` and `disable`",
295332
));
296333
}
334+
if pretty_args.len() == 1 && format_enter_args.len() == 1 {
335+
errors.push(syn::Error::new(
336+
pretty_args[0].0,
337+
"cannot have both `pretty` and `format_enter`",
338+
));
339+
errors.push(syn::Error::new(
340+
format_enter_args[0].0,
341+
"cannot have both `pretty` and `format_enter`",
342+
));
343+
}
344+
if pretty_args.len() == 1 && format_exit_args.len() == 1 {
345+
errors.push(syn::Error::new(
346+
pretty_args[0].0,
347+
"cannot have both `pretty` and `format_exit`",
348+
));
349+
errors.push(syn::Error::new(
350+
format_exit_args[0].0,
351+
"cannot have both `pretty` and `format_exit`",
352+
));
353+
}
297354

298355
if errors.is_empty() {
299356
macro_rules! first_no_span {
@@ -306,6 +363,8 @@ impl Args {
306363
.unwrap_or_else(|| DEFAULT_PREFIX_ENTER.to_owned());
307364
let prefix_exit =
308365
first_no_span!(prefix_exit_args).unwrap_or_else(|| DEFAULT_PREFIX_EXIT.to_owned());
366+
let format_enter = first_no_span!(format_enter_args);
367+
let format_exit = first_no_span!(format_exit_args);
309368
let filter = match (first_no_span!(enable_args), first_no_span!(disable_args)) {
310369
(None, None) => Filter::None,
311370
(Some(idents), None) => Filter::Enable(idents),
@@ -323,6 +382,8 @@ impl Args {
323382
pause,
324383
pretty,
325384
logging,
385+
format_enter,
386+
format_exit,
326387
})
327388
} else {
328389
Err(errors)

0 commit comments

Comments
 (0)