Skip to content

Commit 9fdb1e2

Browse files
committed
Add 'skip' field attribute
1 parent af4b5cb commit 9fdb1e2

File tree

2 files changed

+80
-38
lines changed

2 files changed

+80
-38
lines changed

README.md

+9-5
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,32 @@ Derive `Debug` with a custom format per field.
44

55
# Usage
66

7+
Here is a showcase of all possible field attributes:
8+
79
```rust
810
#[macro_use] extern crate custom_debug_derive;
911
use std::fmt;
1012

1113
#[derive(CustomDebug)]
1214
struct Foo {
1315
#[debug(format = "{} things")]
14-
n: i32,
16+
x: f32,
17+
#[debug(skip)]
18+
y: f32,
1519
#[debug(with = "hex_fmt")]
16-
m: i32,
20+
z: f32,
1721
}
1822

1923
fn hex_fmt<T: fmt::Debug>(n: &T, f: &mut fmt::Formatter) -> fmt::Result {
2024
write!(f, "0x{:02X?}", n)
2125
}
2226
```
2327

24-
Would print something like
28+
The resulting debug output would look something like this:
2529

2630
```
2731
Foo {
28-
n: 42 things,
29-
m: 0xAB
32+
x: 42 things,
33+
z: 0xAB
3034
}
3135
```

src/lib.rs

+71-33
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ extern crate syn;
44

55
use proc_macro2::TokenStream;
66
use synstructure::Structure;
7-
use syn::{Fields, Meta, NestedMeta, Lit, Path, parse_str};
7+
use syn::{Fields, Meta, NestedMeta, Lit, Path, Ident, parse_str};
88

99
decl_derive!([CustomDebug, attributes(debug)] => custom_debug_derive);
1010

1111
fn custom_debug_derive(s: Structure) -> TokenStream {
1212
let name = s.ast().ident.to_string();
13-
let debug_attr = parse_str("debug").unwrap();
13+
let debug_attr = parse_str::<Path>("debug").unwrap();
14+
let skip_ident = parse_str::<Ident>("skip").unwrap();
1415

1516
let variants = s.each_variant(|variant| {
1617
let debug_helper = match variant.ast().fields {
@@ -22,48 +23,52 @@ fn custom_debug_derive(s: Structure) -> TokenStream {
2223
let variant_body = variant.bindings().iter().map(|b| {
2324
let mut format = None;
2425

25-
b.ast().attrs.iter()
26+
let metas = b.ast().attrs.iter()
2627
.filter(|attr| attr.path == debug_attr)
2728
.flat_map(|attr| attr.interpret_meta())
2829
.flat_map(|meta| match meta {
2930
Meta::List(list) => list.nested,
3031
_ => panic!("Invalid debug attribute"),
31-
})
32-
.for_each(|meta| match meta {
33-
NestedMeta::Meta(Meta::NameValue(nv)) => {
34-
let value = nv.lit;
35-
format = Some(match &*nv.ident.to_string() {
36-
"format" => quote! { &format_args!(#value, #b) },
37-
"with" => match value {
38-
Lit::Str(fun) => {
39-
let fun = fun.parse::<Path>().unwrap();
40-
quote! {
41-
&{
42-
struct DebugWith<'a, T: 'a> {
43-
data: &'a T,
44-
fmt: fn(&T, &mut ::std::fmt::Formatter) -> ::std::fmt::Result,
45-
}
32+
});
4633

47-
impl<'a, T: 'a> ::std::fmt::Debug for DebugWith<'a, T> {
48-
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
49-
(self.fmt)(self.data, f)
34+
for meta in metas {
35+
match meta {
36+
NestedMeta::Meta(Meta::Word(ref ident)) if ident == &skip_ident => return quote! {},
37+
NestedMeta::Meta(Meta::NameValue(nv)) => {
38+
let value = nv.lit;
39+
format = Some(match &*nv.ident.to_string() {
40+
"format" => quote! { &format_args!(#value, #b) },
41+
"with" => match value {
42+
Lit::Str(fun) => {
43+
let fun = fun.parse::<Path>().unwrap();
44+
quote! {
45+
&{
46+
struct DebugWith<'a, T: 'a> {
47+
data: &'a T,
48+
fmt: fn(&T, &mut ::std::fmt::Formatter) -> ::std::fmt::Result,
49+
}
50+
51+
impl<'a, T: 'a> ::std::fmt::Debug for DebugWith<'a, T> {
52+
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
53+
(self.fmt)(self.data, f)
54+
}
5055
}
51-
}
5256

53-
DebugWith {
54-
data: #b,
55-
fmt: #fun,
57+
DebugWith {
58+
data: #b,
59+
fmt: #fun,
60+
}
5661
}
5762
}
58-
}
63+
},
64+
_ => panic!("Invalid 'with' value"),
5965
},
60-
_ => panic!("Invalid 'with' value"),
61-
},
62-
name => panic!("Unknown key '{}'", name),
63-
})
64-
},
65-
_ => panic!("Invalid debug attribute"),
66-
});
66+
name => panic!("Unknown key '{}'", name),
67+
})
68+
},
69+
_ => panic!("Invalid debug attribute"),
70+
}
71+
}
6772

6873
let format = format.unwrap_or_else(|| quote! { #b });
6974

@@ -208,6 +213,39 @@ fn test_with() {
208213
}
209214
}
210215

216+
#[test]
217+
fn test_skip() {
218+
test_derive! {
219+
custom_debug_derive {
220+
struct Point {
221+
x: f32,
222+
#[debug(skip)]
223+
y: f32,
224+
z: f32,
225+
}
226+
}
227+
228+
expands to {
229+
#[allow(non_upper_case_globals)]
230+
const _DERIVE_std_fmt_Debug_FOR_Point: () = {
231+
impl ::std::fmt::Debug for Point {
232+
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
233+
match self {
234+
Point { x: ref __binding_0, y: ref __binding_1, z: ref __binding_2, } => {
235+
let mut s = f.debug_struct("Point");
236+
s.field("x", __binding_0);
237+
s.field("z", __binding_2);
238+
s.finish()
239+
}
240+
}
241+
}
242+
}
243+
};
244+
}
245+
246+
no_build
247+
}
248+
}
211249

212250
#[test]
213251
fn test_enum() {

0 commit comments

Comments
 (0)