Skip to content

Commit 2e0bca6

Browse files
authored
Merge pull request #19 from panicbit/18-upgrade-syn-synstructure
18 upgrade syn synstructure
2 parents 8e0f811 + cfeb184 commit 2e0bca6

6 files changed

Lines changed: 146 additions & 127 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/filter_ext.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@ use synstructure::Structure;
44

55
use syn::Result;
66

7-
pub(crate) trait FilterExt {
7+
pub(crate) trait RetainExt {
88
type Item<'a>;
99

10-
fn filter<F>(&mut self, f: F) -> &mut Self
10+
fn retain<F>(&mut self, f: F) -> &mut Self
1111
where
1212
F: for<'a> FnMut(Self::Item<'a>) -> bool;
1313

14-
fn try_filter<F>(&mut self, mut f: F) -> Result<&mut Self>
14+
fn try_retain<F>(&mut self, mut f: F) -> Result<&mut Self>
1515
where
1616
F: for<'a> FnMut(Self::Item<'a>) -> Result<bool>,
1717
{
1818
let mut filter_err = None;
1919

20-
let result = self.filter(|value| {
20+
let result = self.retain(|value| {
2121
if filter_err.is_some() {
2222
return false;
2323
}
@@ -32,10 +32,10 @@ pub(crate) trait FilterExt {
3232
}
3333
}
3434

35-
impl FilterExt for Structure<'_> {
35+
impl RetainExt for Structure<'_> {
3636
type Item<'a> = &'a BindingInfo<'a>;
3737

38-
fn filter<F>(&mut self, mut f: F) -> &mut Self
38+
fn retain<F>(&mut self, mut f: F) -> &mut Self
3939
where
4040
F: for<'a> FnMut(&'a BindingInfo<'a>) -> bool,
4141
{

custom_debug_derive/src/lib.rs

Lines changed: 42 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
use itertools::Itertools;
1+
use darling::FromMeta;
22
use proc_macro2::TokenStream;
33
use quote::quote;
4-
use syn::spanned::Spanned;
5-
use syn::{parse_str, Fields, Ident, Lit, Meta, NestedMeta, Path, Result};
4+
use syn::{Fields, Result};
65
use synstructure::{decl_derive, AddBounds, BindingInfo, Structure, VariantInfo};
76

8-
use crate::filter_ext::FilterExt;
9-
use crate::macros::{bail, error};
7+
use crate::field_attributes::{DebugFormat, FieldAttributes};
8+
use crate::filter_ext::RetainExt;
109
use crate::result_into_stream_ext::ResultIntoStreamExt;
1110

11+
mod field_attributes;
1212
mod filter_ext;
13-
mod macros;
1413
mod result_into_stream_ext;
1514
#[cfg(test)]
1615
mod tests;
@@ -37,24 +36,10 @@ fn custom_debug_derive(mut structure: Structure) -> Result<TokenStream> {
3736
}
3837

3938
fn filter_out_skipped_fields(structure: &mut Structure) -> Result<()> {
40-
let skip_ident: Ident = parse_str("skip").unwrap();
41-
42-
structure.try_filter(|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-
}
39+
structure.try_retain(|binding| {
40+
let field_attributes = parse_field_attributes(binding)?;
5641

57-
Ok(true)
42+
Ok(!field_attributes.skip)
5843
})?;
5944

6045
Ok(())
@@ -82,20 +67,8 @@ fn generate_match_arm_body(variant: &VariantInfo) -> Result<TokenStream> {
8267
}
8368

8469
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 });
70+
let field_attributes = parse_field_attributes(binding)?;
71+
let format = generate_debug_impl(binding, &field_attributes.debug_format);
9972

10073
let debug_builder_call =
10174
if let Some(ref name) = binding.ast().ident.as_ref().map(<_>::to_string) {
@@ -111,70 +84,44 @@ fn generate_debug_builder_call(binding: &BindingInfo) -> Result<TokenStream> {
11184
Ok(debug_builder_call)
11285
}
11386

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-
}
87+
fn generate_debug_impl(binding: &BindingInfo, debug_format: &DebugFormat) -> TokenStream {
88+
match debug_format {
89+
DebugFormat::Default => quote! { #binding },
90+
DebugFormat::Format(format) => quote! { &format_args!(#format, #binding) },
91+
DebugFormat::With(with) => quote! {
92+
{
93+
struct DebugWith<'a, T: 'a> {
94+
data: &'a T,
95+
fmt: fn(&T, &mut ::core::fmt::Formatter) -> ::core::fmt::Result,
96+
}
97+
98+
impl<'a, T: 'a> ::core::fmt::Debug for DebugWith<'a, T> {
99+
fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
100+
(self.fmt)(self.data, fmt)
152101
}
153-
})
102+
}
103+
104+
&DebugWith {
105+
data: #binding,
106+
fmt: #with,
107+
}
154108
}
155-
_ => bail!(value_span, "Invalid `with` value"),
156109
},
157-
_ => bail!(key_span, "Unsupported attribute"),
158110
}
159111
}
160112

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();
113+
fn parse_field_attributes(binding: &BindingInfo<'_>) -> Result<FieldAttributes> {
114+
let mut combined_field_attributes = FieldAttributes::default();
165115

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()?;
116+
for attr in &binding.ast().attrs {
117+
if !attr.path().is_ident("debug") {
118+
continue;
119+
}
173120

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

custom_debug_derive/src/macros.rs

Lines changed: 0 additions & 17 deletions
This file was deleted.

custom_debug_derive/src/result_into_stream_ext.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
use syn::Result;
2-
3-
use syn;
4-
51
use proc_macro2::TokenStream;
62

73
pub(crate) trait ResultIntoStreamExt {

0 commit comments

Comments
 (0)