Skip to content

Commit 3d05978

Browse files
authored
Update syn to 2.0 (#119)
1 parent 92d62c0 commit 3d05978

File tree

3 files changed

+105
-87
lines changed

3 files changed

+105
-87
lines changed

influxdb_derive/Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ repository = "https://github.com/influxdb-rs/influxdb-rust"
1616
proc-macro = true
1717

1818
[dependencies]
19-
proc-macro2 = "1.0.9"
20-
quote = "1.0.3"
21-
syn = { version = "1.0.16", features = ["extra-traits", "full"] }
19+
proc-macro2 = "1.0"
20+
quote = "1.0"
21+
syn = { version = "2.0", features = ["extra-traits", "full"] }

influxdb_derive/src/lib.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
use proc_macro::TokenStream;
2-
use proc_macro2::TokenStream as TokenStream2;
3-
use quote::quote;
42

53
mod writeable;
4+
use syn::parse_macro_input;
65
use writeable::expand_writeable;
76

8-
fn krate() -> TokenStream2 {
9-
quote!(::influxdb)
10-
}
11-
127
#[proc_macro_derive(InfluxDbWriteable, attributes(influxdb))]
13-
pub fn derive_writeable(tokens: TokenStream) -> TokenStream {
14-
expand_writeable(tokens)
8+
pub fn derive_writeable(input: TokenStream) -> TokenStream {
9+
expand_writeable(parse_macro_input!(input))
10+
.unwrap_or_else(syn::Error::into_compile_error)
11+
.into()
1512
}

influxdb_derive/src/writeable.rs

+97-76
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
use proc_macro::TokenStream;
2-
use proc_macro2::{TokenStream as TokenStream2, TokenTree};
1+
use proc_macro2::TokenStream;
32
use quote::{format_ident, quote};
4-
use syn::{parse_macro_input, Field, Fields, Ident, ItemStruct};
3+
use std::convert::TryFrom;
4+
use syn::{
5+
parse::{Parse, ParseStream},
6+
punctuated::Punctuated,
7+
Data, DeriveInput, Field, Fields, Ident, Meta, Token,
8+
};
59

610
#[derive(Debug)]
711
struct WriteableField {
@@ -10,108 +14,125 @@ struct WriteableField {
1014
is_ignore: bool,
1115
}
1216

13-
impl From<Field> for WriteableField {
14-
fn from(field: Field) -> WriteableField {
15-
let ident = field.ident.expect("fields without ident are not supported");
17+
mod kw {
18+
use syn::custom_keyword;
1619

17-
let check_influx_aware = |attr: &syn::Attribute| -> bool {
18-
attr.path
19-
.segments
20-
.iter()
21-
.last()
22-
.map(|seg| seg.ident.to_string())
23-
.unwrap_or_default()
24-
== "influxdb"
25-
};
20+
custom_keyword!(tag);
21+
custom_keyword!(ignore);
22+
}
2623

27-
let check_for_attr = |token_tree, ident_cmp: &str| -> bool {
28-
match token_tree {
29-
TokenTree::Group(group) => group
30-
.stream()
31-
.into_iter()
32-
.next()
33-
.map(|token_tree| match token_tree {
34-
TokenTree::Ident(ident) => ident == ident_cmp,
35-
_ => false,
36-
})
37-
.unwrap(),
38-
_ => false,
39-
}
40-
};
24+
enum FieldAttr {
25+
Tag(kw::tag),
26+
Ignore(kw::ignore),
27+
}
4128

42-
let is_ignore = field.attrs.iter().any(|attr| {
43-
if !check_influx_aware(attr) {
44-
return false;
45-
}
29+
impl Parse for FieldAttr {
30+
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
31+
let lookahead = input.lookahead1();
32+
if lookahead.peek(kw::tag) {
33+
Ok(Self::Tag(input.parse()?))
34+
} else if lookahead.peek(kw::ignore) {
35+
Ok(Self::Ignore(input.parse()?))
36+
} else {
37+
Err(lookahead.error())
38+
}
39+
}
40+
}
41+
42+
struct FieldAttrs(Punctuated<FieldAttr, Token![,]>);
43+
44+
impl Parse for FieldAttrs {
45+
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
46+
Ok(Self(Punctuated::parse_terminated(input)?))
47+
}
48+
}
4649

47-
attr.tokens
48-
.clone()
49-
.into_iter()
50-
.next()
51-
.map(|token_tree| check_for_attr(token_tree, "ignore"))
52-
.unwrap()
53-
});
50+
impl TryFrom<Field> for WriteableField {
51+
type Error = syn::Error;
5452

55-
let is_tag = field.attrs.iter().any(|attr| {
56-
if !check_influx_aware(attr) {
57-
return false;
53+
fn try_from(field: Field) -> syn::Result<WriteableField> {
54+
let ident = field.ident.expect("fields without ident are not supported");
55+
let mut is_tag = false;
56+
let mut is_ignore = false;
57+
58+
for attr in field.attrs {
59+
match attr.meta {
60+
Meta::List(list) if list.path.is_ident("influxdb") => {
61+
for attr in syn::parse2::<FieldAttrs>(list.tokens)?.0 {
62+
match attr {
63+
FieldAttr::Tag(_) => is_tag = true,
64+
FieldAttr::Ignore(_) => is_ignore = true,
65+
}
66+
}
67+
}
68+
_ => {}
5869
}
59-
attr.tokens
60-
.clone()
61-
.into_iter()
62-
.next()
63-
.map(|token_tree| check_for_attr(token_tree, "tag"))
64-
.unwrap()
65-
});
70+
}
6671

67-
WriteableField {
72+
Ok(WriteableField {
6873
ident,
6974
is_tag,
7075
is_ignore,
71-
}
76+
})
7277
}
7378
}
7479

75-
pub fn expand_writeable(tokens: TokenStream) -> TokenStream {
76-
let krate = super::krate();
77-
let input = parse_macro_input!(tokens as ItemStruct);
80+
pub fn expand_writeable(input: DeriveInput) -> syn::Result<TokenStream> {
7881
let ident = input.ident;
79-
let generics = input.generics;
82+
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
83+
84+
let fields = match input.data {
85+
Data::Struct(strukt) => strukt.fields,
86+
Data::Enum(inum) => {
87+
return Err(syn::Error::new(
88+
inum.enum_token.span,
89+
"#[derive(InfluxDbWriteable)] can only be used on structs",
90+
))
91+
}
92+
Data::Union(cdu) => {
93+
return Err(syn::Error::new(
94+
cdu.union_token.span,
95+
"#[derive(InfluxDbWriteable)] can only be used on structs",
96+
))
97+
}
98+
};
8099

81100
let time_field = format_ident!("time");
101+
let time_field_str = time_field.to_string();
82102
#[allow(clippy::cmp_owned)] // that's not how idents work clippy
83-
let fields: Vec<TokenStream2> = match input.fields {
103+
let fields = match fields {
84104
Fields::Named(fields) => fields
85105
.named
86106
.into_iter()
87-
.map(WriteableField::from)
88-
.filter(|field| !field.is_ignore)
89-
.filter(|field| field.ident.to_string() != time_field.to_string())
90-
.map(|field| {
91-
let ident = field.ident;
92-
#[allow(clippy::match_bool)]
93-
match field.is_tag {
94-
true => quote!(query.add_tag(stringify!(#ident), self.#ident)),
95-
false => quote!(query.add_field(stringify!(#ident), self.#ident)),
96-
}
107+
.filter_map(|f| {
108+
WriteableField::try_from(f)
109+
.map(|wf| {
110+
if !wf.is_ignore && wf.ident.to_string() != time_field_str {
111+
let ident = wf.ident;
112+
Some(match wf.is_tag {
113+
true => quote!(query.add_tag(stringify!(#ident), self.#ident)),
114+
false => quote!(query.add_field(stringify!(#ident), self.#ident)),
115+
})
116+
} else {
117+
None
118+
}
119+
})
120+
.transpose()
97121
})
98-
.collect(),
122+
.collect::<syn::Result<Vec<_>>>()?,
99123
_ => panic!("a struct without named fields is not supported"),
100124
};
101125

102-
let output = quote! {
103-
impl #generics #krate::InfluxDbWriteable for #ident #generics
104-
{
105-
fn into_query<I: Into<String>>(self, name : I) -> #krate::WriteQuery
106-
{
107-
let timestamp : #krate::Timestamp = self.#time_field.into();
126+
Ok(quote! {
127+
impl #impl_generics ::influxdb::InfluxDbWriteable for #ident #ty_generics #where_clause {
128+
fn into_query<I: Into<String>>(self, name: I) -> ::influxdb::WriteQuery {
129+
let timestamp: ::influxdb::Timestamp = self.#time_field.into();
108130
let mut query = timestamp.into_query(name);
109131
#(
110132
query = #fields;
111133
)*
112134
query
113135
}
114136
}
115-
};
116-
output.into()
137+
})
117138
}

0 commit comments

Comments
 (0)