Skip to content

Commit fcb5088

Browse files
committed
upgrade to syn 2.0
1 parent aaba01f commit fcb5088

3 files changed

Lines changed: 138 additions & 94 deletions

File tree

custom_debug_derive/Cargo.toml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ edition = "2021"
1212
proc-macro = true
1313

1414
[dependencies]
15-
synstructure = "0.12.3"
16-
proc-macro2 = "1.0.6"
17-
syn = "1.0.11"
18-
quote = "1.0.23"
19-
itertools = "0.10.5"
15+
synstructure = "0.13.0"
16+
proc-macro2 = "1.0.76"
17+
syn = "2.0.48"
18+
quote = "1.0.35"
19+
itertools = "0.12.0"
20+
darling = "0.20.3"
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
use std::cell::OnceCell;
2+
3+
use darling::util::Flag;
4+
use darling::FromMeta;
5+
use syn::ExprPath;
6+
7+
#[derive(Default)]
8+
pub struct FieldAttributes {
9+
pub skip: bool,
10+
pub debug_format: DebugFormat,
11+
}
12+
13+
impl FieldAttributes {
14+
fn new(internal: InternalFieldAttributes) -> darling::Result<Self> {
15+
let skip = internal.skip.is_present();
16+
let debug_format = OnceCell::new();
17+
18+
if let Some(format) = internal.format {
19+
debug_format
20+
.set(DebugFormat::Format(format))
21+
.map_err(|_| conflicting_format_options_error())?;
22+
}
23+
24+
if let Some(with) = internal.with {
25+
debug_format
26+
.set(DebugFormat::With(with))
27+
.map_err(|_| conflicting_format_options_error())?;
28+
}
29+
30+
let debug_format = debug_format.into_inner().unwrap_or(DebugFormat::Default);
31+
32+
Ok(Self { skip, debug_format })
33+
}
34+
35+
pub fn try_combine(self, other: Self) -> darling::Result<Self> {
36+
let skip = self.skip || other.skip;
37+
let debug_format = self.debug_format.try_combine(other.debug_format)?;
38+
39+
Ok(Self { skip, debug_format })
40+
}
41+
}
42+
43+
impl FromMeta for FieldAttributes {
44+
fn from_nested_meta(item: &darling::ast::NestedMeta) -> darling::Result<Self> {
45+
InternalFieldAttributes::from_nested_meta(item).and_then(FieldAttributes::new)
46+
}
47+
48+
fn from_meta(item: &syn::Meta) -> darling::Result<Self> {
49+
InternalFieldAttributes::from_meta(item).and_then(FieldAttributes::new)
50+
}
51+
52+
fn from_none() -> Option<Self> {
53+
InternalFieldAttributes::from_none().and_then(|attrs| FieldAttributes::new(attrs).ok())
54+
}
55+
56+
fn from_word() -> darling::Result<Self> {
57+
InternalFieldAttributes::from_word().and_then(FieldAttributes::new)
58+
}
59+
60+
fn from_list(items: &[darling::ast::NestedMeta]) -> darling::Result<Self> {
61+
InternalFieldAttributes::from_list(items).and_then(FieldAttributes::new)
62+
}
63+
}
64+
65+
#[derive(FromMeta, Debug, PartialEq, Eq, Default)]
66+
pub enum DebugFormat {
67+
#[default]
68+
Default,
69+
Format(String),
70+
With(ExprPath),
71+
}
72+
73+
impl DebugFormat {
74+
fn try_combine(self, other: Self) -> darling::Result<Self> {
75+
match (&self, &other) {
76+
(DebugFormat::Default, _) => Ok(other),
77+
(_, DebugFormat::Default) => Ok(self),
78+
_ => Err(conflicting_format_options_error()),
79+
}
80+
}
81+
}
82+
83+
#[derive(FromMeta)]
84+
struct InternalFieldAttributes {
85+
skip: Flag,
86+
format: Option<String>,
87+
with: Option<ExprPath>,
88+
}
89+
90+
fn conflicting_format_options_error() -> darling::Error {
91+
darling::Error::custom("Conflicting format options")
92+
}

custom_debug_derive/src/lib.rs

Lines changed: 40 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1+
use darling::FromMeta;
12
use itertools::Itertools;
23
use proc_macro2::TokenStream;
34
use quote::quote;
45
use syn::spanned::Spanned;
5-
use syn::{parse_str, Fields, Ident, Lit, Meta, NestedMeta, Path, Result};
6+
use syn::{parse_str, Fields, Ident, Lit, Meta, Path, Result};
67
use synstructure::{decl_derive, AddBounds, BindingInfo, Structure, VariantInfo};
78

9+
use crate::field_attributes::{DebugFormat, FieldAttributes};
810
use crate::filter_ext::RetainExt;
911
use crate::macros::{bail, error};
1012
use crate::result_into_stream_ext::ResultIntoStreamExt;
1113

14+
mod field_attributes;
1215
mod filter_ext;
1316
mod macros;
1417
mod result_into_stream_ext;
@@ -37,24 +40,10 @@ fn custom_debug_derive(mut structure: Structure) -> Result<TokenStream> {
3740
}
3841

3942
fn filter_out_skipped_fields(structure: &mut Structure) -> Result<()> {
40-
let skip_ident: Ident = parse_str("skip").unwrap();
41-
4243
structure.try_retain(|binding| {
43-
for meta in get_custom_debug_metas(binding) {
44-
let meta = meta?;
45-
46-
if let NestedMeta::Meta(Meta::Path(ref path)) = meta {
47-
if path
48-
.get_ident()
49-
.map(|ident| ident == &skip_ident)
50-
.unwrap_or(false)
51-
{
52-
return Ok(false);
53-
}
54-
}
55-
}
44+
let field_attributes = parse_field_attributes(binding)?;
5645

57-
Ok(true)
46+
Ok(!field_attributes.skip)
5847
})?;
5948

6049
Ok(())
@@ -82,20 +71,8 @@ fn generate_match_arm_body(variant: &VariantInfo) -> Result<TokenStream> {
8271
}
8372

8473
fn generate_debug_builder_call(binding: &BindingInfo) -> Result<TokenStream> {
85-
let mut format = None;
86-
87-
for meta in get_custom_debug_metas(binding) {
88-
let meta = meta?;
89-
90-
match meta {
91-
NestedMeta::Meta(Meta::NameValue(nv)) => {
92-
format = Some(generate_name_value_builder_call(binding, nv)?)
93-
}
94-
_ => bail!(meta.span(), "Unsupported attribute"),
95-
}
96-
}
97-
98-
let format = format.unwrap_or_else(|| quote! { #binding });
74+
let field_attributes = parse_field_attributes(binding)?;
75+
let format = generate_debug_impl(binding, &field_attributes.debug_format);
9976

10077
let debug_builder_call =
10178
if let Some(ref name) = binding.ast().ident.as_ref().map(<_>::to_string) {
@@ -111,70 +88,44 @@ fn generate_debug_builder_call(binding: &BindingInfo) -> Result<TokenStream> {
11188
Ok(debug_builder_call)
11289
}
11390

114-
fn generate_name_value_builder_call(
115-
binding: &BindingInfo,
116-
nv: syn::MetaNameValue,
117-
) -> Result<TokenStream> {
118-
let key_span = nv.path.span();
119-
let value_span = nv.lit.span();
120-
let value = nv.lit;
121-
let ident = nv
122-
.path
123-
.get_ident()
124-
.map(Ident::to_string)
125-
.ok_or_else(|| error!(key_span, "Unsupported attribute"))?;
126-
127-
match &*ident {
128-
"format" => Ok(quote! { &format_args!(#value, #binding) }),
129-
"with" => match value {
130-
Lit::Str(fun) => {
131-
let fun = fun
132-
.parse::<Path>()
133-
.map_err(|_| error!(fun.span(), "Invalid path to function"))?;
134-
135-
Ok(quote! {
136-
{
137-
struct DebugWith<'a, T: 'a> {
138-
data: &'a T,
139-
fmt: fn(&T, &mut ::core::fmt::Formatter) -> ::core::fmt::Result,
140-
}
141-
142-
impl<'a, T: 'a> ::core::fmt::Debug for DebugWith<'a, T> {
143-
fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
144-
(self.fmt)(self.data, fmt)
145-
}
146-
}
147-
148-
&DebugWith {
149-
data: #binding,
150-
fmt: #fun,
151-
}
91+
fn generate_debug_impl(binding: &BindingInfo, debug_format: &DebugFormat) -> TokenStream {
92+
match debug_format {
93+
DebugFormat::Default => quote! { #binding },
94+
DebugFormat::Format(format) => quote! { &format_args!(#format, #binding) },
95+
DebugFormat::With(with) => quote! {
96+
{
97+
struct DebugWith<'a, T: 'a> {
98+
data: &'a T,
99+
fmt: fn(&T, &mut ::core::fmt::Formatter) -> ::core::fmt::Result,
100+
}
101+
102+
impl<'a, T: 'a> ::core::fmt::Debug for DebugWith<'a, T> {
103+
fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
104+
(self.fmt)(self.data, fmt)
152105
}
153-
})
106+
}
107+
108+
&DebugWith {
109+
data: #binding,
110+
fmt: #with,
111+
}
154112
}
155-
_ => bail!(value_span, "Invalid `with` value"),
156113
},
157-
_ => bail!(key_span, "Unsupported attribute"),
158114
}
159115
}
160116

161-
fn get_custom_debug_metas<'a>(
162-
binding: &BindingInfo<'a>,
163-
) -> impl Iterator<Item = Result<NestedMeta>> + 'a {
164-
let debug_attr = parse_str::<Path>("debug").unwrap();
117+
fn parse_field_attributes(binding: &BindingInfo<'_>) -> Result<FieldAttributes> {
118+
let mut combined_field_attributes = FieldAttributes::default();
165119

166-
binding
167-
.ast()
168-
.attrs
169-
.iter()
170-
.filter(move |attr| attr.path == debug_attr)
171-
.map(|attr| {
172-
let meta = attr.parse_meta()?;
120+
for attr in &binding.ast().attrs {
121+
if !attr.path().is_ident("debug") {
122+
continue;
123+
}
173124

174-
match meta {
175-
Meta::List(list) => Ok(list.nested),
176-
_ => bail!(meta.span(), "Unsupported attribute style, use `debug(…)`"),
177-
}
178-
})
179-
.flatten_ok()
125+
let field_attributes = FieldAttributes::from_meta(&attr.meta)?;
126+
127+
combined_field_attributes = combined_field_attributes.try_combine(field_attributes)?;
128+
}
129+
130+
Ok(combined_field_attributes)
180131
}

0 commit comments

Comments
 (0)