1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#![forbid(unsafe_code)]
#![deny(missing_docs)]
extern crate proc_macro;
mod attributes;
mod constants;
mod index;
mod util;
mod warp;
use derive_new::new;
use proc_macro2::TokenStream;
use proc_macro_error::{abort_call_site, proc_macro_error, set_dummy};
use quote::quote;
use syn::{punctuated::Punctuated, token::Comma, *};
pub(crate) const DEFAULT_ROOT_PATH: &str = "config";
pub(crate) const DEFAULT_ROOT_MESSAGE: &str = "Available configuration options:";
#[derive(new)]
pub(crate) struct GenChoicesOutput {
macro_block: TokenStream,
impl_block: TokenStream,
trait_block: TokenStream,
}
#[proc_macro_derive(Choices, attributes(choices))]
#[proc_macro_error]
pub fn choices(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input: DeriveInput = syn::parse(input).unwrap();
let gen = impl_choices(&input);
gen.into()
}
fn impl_choices(input: &DeriveInput) -> TokenStream {
use syn::Data::*;
let struct_name = &input.ident;
set_dummy(quote! {
#[choices::async_trait]
impl ::choices::Choices for #struct_name {
unimplemented!();
}
});
match input.data {
Struct(DataStruct {
fields: syn::Fields::Named(ref fields),
..
}) => impl_choices_for_struct(struct_name, &fields.named, &input.attrs),
_ => abort_call_site!("choices only supports non-tuple structs"),
}
}
fn impl_choices_for_struct(
name: &Ident,
fields: &Punctuated<Field, Comma>,
attrs: &[Attribute],
) -> TokenStream {
let choices = warp::gen_choices(fields, attrs);
let macro_block = choices.macro_block;
let impl_block = choices.impl_block;
let trait_block = choices.trait_block;
quote! {
#macro_block
#[allow(unused_variables)]
#[allow(unknown_lints)]
#[allow(
clippy::style,
clippy::complexity,
clippy::pedantic,
clippy::restriction,
clippy::perf,
clippy::deprecated,
clippy::nursery,
clippy::cargo
)]
#[deny(clippy::correctness)]
#[allow(dead_code, unreachable_code)]
impl #name {
#impl_block
}
#[allow(unused_variables)]
#[allow(unknown_lints)]
#[allow(
clippy::style,
clippy::complexity,
clippy::pedantic,
clippy::restriction,
clippy::perf,
clippy::deprecated,
clippy::nursery,
clippy::cargo
)]
#[deny(clippy::correctness)]
#[allow(dead_code, unreachable_code)]
#[choices::async_trait]
impl ::choices::Choices for #name {
#trait_block
}
}
}