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
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields};
#[proc_macro_derive(UpdateFspec)]
#[doc(hidden)]
pub fn derive_answer_fn(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let mut data_items: Vec<(String, String, String)> = vec![];
if let Data::Struct(s) = input.data {
if let Fields::Named(f) = s.fields {
for field in f.named.iter() {
let ident = field.ident.as_ref().unwrap();
if ident == "fspec" {
continue;
}
for att in &field.attrs {
if att.path.segments[0].ident == "doc" {
continue;
}
let s: String = format!("{}", att.tokens);
let s = &s[7..s.len() - 1];
let lpos = s.find('(').unwrap() + 1;
let comma = s.find(',').unwrap();
let fspec_pos = s.rfind(')').unwrap() - 1;
let frn = &s[lpos..comma];
let fspec = &s[fspec_pos as usize..=fspec_pos as usize];
data_items.push((ident.to_string(), fspec.to_string(), frn.to_string()));
}
}
}
}
let mut quotes = quote! {};
for data_item in data_items {
let ident = syn::Ident::new(&data_item.0.to_string(), syn::export::Span::call_site());
let fspec_num = data_item.1.parse::<usize>().unwrap();
let frn = data_item.2;
let frn = syn::parse_str::<syn::Expr>(&frn).unwrap();
quotes = quote! {
#quotes
if self.#ident.is_some() {
fspec[#fspec_num] |= #frn;
}
}
}
let expanded = quote! {
impl #name {
pub fn update_fspec(&mut self) {
let mut fspec = vec![0x00; 10];
#quotes
trim_fspec(&mut fspec);
add_fx(&mut fspec);
self.fspec = fspec;
}
}
};
TokenStream::from(expanded)
}