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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#![recursion_limit = "128"]
extern crate syn;
use syn::{Ident, Body, MetaItem, NestedMetaItem, Lit};
use quote::Tokens;
#[macro_use]
extern crate quote;
extern crate proc_macro;
use proc_macro::TokenStream;
#[derive(Clone)]
struct InstrumentField { name: String, ident: Ident }
#[proc_macro_derive(Instruments, attributes(rapt))]
pub fn derive_instruments(input: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&input.to_string()).unwrap();
let ident = input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let listener_ident = &input.generics.ty_params.iter().last().unwrap().ident;
let dummy_const = Ident::new(format!("_IMPL_INSTRUMENTS_FOR_{}", ident));
match input.body {
Body::Enum(_) => panic!("enums are not supported for Instruments derivations"),
Body::Struct(variants) => {
let instruments : Vec<InstrumentField> = variants.fields().iter().enumerate()
.map(|(i, f)| {
let overriding_name = match f.attrs.iter()
.find(|a| a.name() == "rapt") {
Some(attr) => match attr.value {
MetaItem::List(_, ref items) =>
items.iter().find(|item| match item {
&&NestedMetaItem::MetaItem(ref item) => item.name() == "name",
_ => false,
}).map(|item| match item {
&NestedMetaItem::MetaItem(MetaItem::NameValue(_, Lit::Str(ref str, _))) => str.clone(),
_ =>
panic!("#[rapt(name = \"...\") attribute can only contain a string value"),
}),
_ => None,
},
None => None,
};
if f.ident.is_none() && overriding_name.is_none() {
panic!("struct {:} can't derive Instruments because field #{:} has no #[rapt(name = \"..\")] attribute", ident, i);
}
let name = if overriding_name.is_some() {
overriding_name.unwrap()
} else {
String::from(f.ident.clone().unwrap().as_ref())
};
InstrumentField { name, ident: f.ident.clone().unwrap() }
}).collect();
let matches : Vec<Tokens> = instruments.clone().into_iter().map(|i| {
let (name, ident) = (i.name, i.ident);
quote!{ #name => self . #ident . serialize(serializer).map_err(|e| _rapt::ReadError::SerializationError(e)) }
}).collect();
let names : Vec<Tokens> = instruments.clone().into_iter().map(|i| {
let name = i.name;
quote!{ #name }
}).collect();
let wirings : Vec<Tokens> = instruments.clone().into_iter().map(|i| {
let (name, ident) = (i.name, i.ident);
quote!{
self . #ident . set_name_and_listener(#name, listener.clone())
}
}).collect();
let impl_block = quote! {
impl #impl_generics _rapt::Instruments<#listener_ident> for #ident #ty_generics #where_clause {
fn serialize_reading<K : AsRef<str>, S: _serde::Serializer>(&self, key: K, serializer: S) -> Result<S::Ok, _rapt::ReadError<S::Error>> {
match key.as_ref() {
#(#matches),*,
_ => Err(_rapt::ReadError::NotFound),
}
}
fn instrument_names(&self) -> Vec<&'static str> {
vec![#(#names),*]
}
fn wire_listener(&mut self, listener: L) {
#(#wirings);*
}
}
};
let generated = quote! {
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const #dummy_const: () = {
extern crate rapt as _rapt;
extern crate serde as _serde;
#impl_block
};
};
generated.parse().unwrap()
},
}
}