Skip to content

Commit 0a462a0

Browse files
committed
config_type: add argument for skipping derives
1 parent ee2bed9 commit 0a462a0

File tree

7 files changed

+98
-14
lines changed

7 files changed

+98
-14
lines changed

config_proc_macro/src/args.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use syn::{
2+
parenthesized,
3+
parse::{Error as ParserError, Parse, ParseStream},
4+
Ident, Token,
5+
};
6+
7+
#[derive(Debug, Default)]
8+
pub struct Args {
9+
pub skip_derive: Option<Vec<String>>,
10+
}
11+
12+
impl Args {
13+
pub fn skip_derives(&self) -> impl Iterator<Item = &str> + '_ {
14+
self.skip_derive
15+
.as_ref()
16+
.into_iter()
17+
.flatten()
18+
.map(|s| s.as_ref())
19+
}
20+
}
21+
22+
impl Parse for Args {
23+
fn parse(input: ParseStream<'_>) -> Result<Self, ParserError> {
24+
let mut args = Self::default();
25+
26+
while !input.is_empty() {
27+
let ident: Ident = input.parse()?;
28+
match ident.to_string().as_str() {
29+
"skip_derive" => {
30+
let content;
31+
parenthesized!(content in input);
32+
args.skip_derive = Some(
33+
content
34+
.parse_terminated::<_, Token![,]>(Ident::parse)?
35+
.into_iter()
36+
.map(|i| i.to_string())
37+
.collect(),
38+
);
39+
}
40+
a => panic!("unknown attribute: {}", a),
41+
}
42+
}
43+
44+
Ok(args)
45+
}
46+
}

config_proc_macro/src/config_type.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use proc_macro2::TokenStream;
22

3+
use crate::args::Args;
34
use crate::item_enum::define_config_type_on_enum;
45
use crate::item_struct::define_config_type_on_struct;
56

67
/// Defines `config_type` on enum or struct.
78
// FIXME: Implement this on struct.
8-
pub fn define_config_type(input: &syn::Item) -> TokenStream {
9+
pub fn define_config_type(args: &Args, input: &syn::Item) -> TokenStream {
910
match input {
10-
syn::Item::Struct(st) => define_config_type_on_struct(st),
11-
syn::Item::Enum(en) => define_config_type_on_enum(en),
11+
syn::Item::Struct(st) => define_config_type_on_struct(args, st),
12+
syn::Item::Enum(en) => define_config_type_on_enum(args, en),
1213
_ => panic!("Expected enum or struct"),
1314
}
1415
.unwrap()

config_proc_macro/src/item_enum.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ use proc_macro2::TokenStream;
22
use quote::{quote, quote_spanned};
33
use syn::spanned::Spanned;
44

5+
use crate::args::Args;
56
use crate::attrs::*;
67
use crate::utils::*;
78

89
type Variants = syn::punctuated::Punctuated<syn::Variant, syn::Token![,]>;
910

1011
/// Defines and implements `config_type` enum.
11-
pub fn define_config_type_on_enum(em: &syn::ItemEnum) -> syn::Result<TokenStream> {
12+
pub fn define_config_type_on_enum(args: &Args, em: &syn::ItemEnum) -> syn::Result<TokenStream> {
1213
let syn::ItemEnum {
1314
vis,
1415
enum_token,
@@ -21,22 +22,46 @@ pub fn define_config_type_on_enum(em: &syn::ItemEnum) -> syn::Result<TokenStream
2122
let mod_name_str = format!("__define_config_type_on_enum_{}", ident);
2223
let mod_name = syn::Ident::new(&mod_name_str, ident.span());
2324
let variants = fold_quote(variants.iter().map(process_variant), |meta| quote!(#meta,));
25+
let derives = [
26+
"std::fmt::Debug",
27+
"std::clone::Clone",
28+
"std::marker::Copy",
29+
"std::cmp::Eq",
30+
"std::cmp::PartialEq",
31+
]
32+
.iter()
33+
.filter(|d| args.skip_derives().all(|s| !d.ends_with(s)))
34+
.map(|d| syn::parse_str(d).unwrap())
35+
.collect::<Vec<syn::Path>>();
36+
let derives = if derives.is_empty() {
37+
quote!()
38+
} else {
39+
quote! { #[derive( #( #derives ),* )] }
40+
};
2441

2542
let impl_doc_hint = impl_doc_hint(&em.ident, &em.variants);
2643
let impl_from_str = impl_from_str(&em.ident, &em.variants);
2744
let impl_display = impl_display(&em.ident, &em.variants);
28-
let impl_serde = impl_serde(&em.ident, &em.variants);
29-
let impl_deserialize = impl_deserialize(&em.ident, &em.variants);
45+
let impl_serialize = if args.skip_derives().any(|s| s == "Serialize") {
46+
quote!()
47+
} else {
48+
impl_serialize(&em.ident, &em.variants)
49+
};
50+
let impl_deserialize = if args.skip_derives().any(|s| s == "Deserialize") {
51+
quote!()
52+
} else {
53+
impl_deserialize(&em.ident, &em.variants)
54+
};
3055

3156
Ok(quote! {
3257
#[allow(non_snake_case)]
3358
mod #mod_name {
34-
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
59+
#derives
3560
pub #enum_token #ident #generics { #variants }
3661
#impl_display
3762
#impl_doc_hint
3863
#impl_from_str
39-
#impl_serde
64+
#impl_serialize
4065
#impl_deserialize
4166
}
4267
#vis use #mod_name::#ident;
@@ -164,7 +189,7 @@ fn unstable_of_variant(variant: &syn::Variant) -> bool {
164189
any_unstable_variant(&variant.attrs)
165190
}
166191

167-
fn impl_serde(ident: &syn::Ident, variants: &Variants) -> TokenStream {
192+
fn impl_serialize(ident: &syn::Ident, variants: &Variants) -> TokenStream {
168193
let arms = fold_quote(variants.iter(), |v| {
169194
let v_ident = &v.ident;
170195
let pattern = match v.fields {

config_proc_macro/src/item_struct.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
use proc_macro2::TokenStream;
22

3-
pub fn define_config_type_on_struct(_st: &syn::ItemStruct) -> syn::Result<TokenStream> {
3+
use crate::args::Args;
4+
5+
pub fn define_config_type_on_struct(
6+
_args: &Args,
7+
_st: &syn::ItemStruct,
8+
) -> syn::Result<TokenStream> {
49
unimplemented!()
510
}

config_proc_macro/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
#![recursion_limit = "256"]
44

5+
mod args;
56
mod attrs;
67
mod config_type;
78
mod item_enum;
@@ -14,9 +15,10 @@ use proc_macro::TokenStream;
1415
use syn::parse_macro_input;
1516

1617
#[proc_macro_attribute]
17-
pub fn config_type(_args: TokenStream, input: TokenStream) -> TokenStream {
18+
pub fn config_type(args: TokenStream, input: TokenStream) -> TokenStream {
19+
let args = parse_macro_input!(args as args::Args);
1820
let input = parse_macro_input!(input as syn::Item);
19-
let output = config_type::define_config_type(&input);
21+
let output = config_type::define_config_type(&args, &input);
2022

2123
#[cfg(feature = "debug-with-rustfmt")]
2224
{

config_proc_macro/src/utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use proc_macro2::TokenStream;
22
use quote::{quote, ToTokens};
33

4-
pub fn fold_quote<F, I, T>(input: impl Iterator<Item = I>, f: F) -> TokenStream
4+
pub fn fold_quote<F, I, T>(input: impl IntoIterator<Item = I>, f: F) -> TokenStream
55
where
66
F: Fn(I) -> T,
77
T: ToTokens,
88
{
9-
input.fold(quote! {}, |acc, x| {
9+
input.into_iter().fold(quote! {}, |acc, x| {
1010
let y = f(x);
1111
quote! { #acc #y }
1212
})

config_proc_macro/tests/smoke.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,9 @@ mod tests {
1818
FooBar,
1919
FooFoo(i32),
2020
}
21+
22+
#[config_type(skip_derive(Copy, Serialize))]
23+
enum X {
24+
Abc(String),
25+
}
2126
}

0 commit comments

Comments
 (0)