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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use quote::{quote, format_ident};
use proc_macro::{TokenStream, Span};
use syn::{
parse_macro_input, DeriveInput, Data, GenericParam, Lifetime, Ident,
};
#[proc_macro_derive(Info)]
pub fn info(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
if let Data::Struct(ref data) = input.data {
let empty = data.fields.is_empty();
let ls = input.generics.params.iter().filter_map(|g| match g {
GenericParam::Lifetime(l) => Some(&l.lifetime), _ => None,
}).collect::<Vec<_>>();
let l = ls.first().map(|&l| l.clone()).unwrap_or_else(|| if empty {
Lifetime::new("'_", Span::call_site().into())
} else {
Lifetime::new("'a", Span::call_site().into())
});
let ol = (ls.is_empty() && !empty).then(|| &l);
let ol1 = ol.iter();
let ol2 = ol.iter();
let ol3 = ol.iter();
let ol4 = ol.iter();
let ol5 = ol.iter();
let ts = input.generics.params.iter().filter_map(|g| match g {
GenericParam::Type(t) => Some(&t.ident), _ => None,
}).collect::<Vec<_>>();
let t = ts.first().map(|&t| t.clone())
.unwrap_or_else(|| Ident::new("T", Span::call_site().into()));
let ot = ts.is_empty().then(|| &t);
let ot = ot.iter();
let bs = input.generics.params.iter().filter_map(|g| match g {
GenericParam::Type(t) => Some(&t.bounds), _ => None,
}).collect::<Vec<_>>();
let cs = input.generics.params.iter().filter_map(|g| match g {
GenericParam::Const(c) => Some(&c.ident), _ => None,
}).collect::<Vec<_>>();
let cts = input.generics.params.iter().filter_map(|g| match g {
GenericParam::Const(c) => Some(&c.ty), _ => None,
}).collect::<Vec<_>>();
let ident = &input.ident;
let cident = format_ident!("{}Ctx", ident);
let mident = format_ident!("{}_ctx", ident.to_string().to_lowercase());
let types = data.fields.iter().map(|t| &t.ty).collect::<Vec<_>>();
let idents = data.fields.iter().map(|i| &i.ident).collect::<Vec<_>>();
TokenStream::from(quote! {
mod #mident {
use super::*;
pub struct #cident<#(#ol1,)* #(#ls,)* #(#ts: #bs,)* #(const #cs: #cts,)*> {
#(pub(super) #idents: <#types as Info<#l, #t>>::Context,)*
}
impl<#(#ol2,)* #(#ls,)* #(#ts: #bs,)* #(const #cs: #cts,)*> Default
for #cident<#(#ol3,)* #(#ls,)* #(#ts,)* #(#cs,)*> {
fn default() -> Self {
Self { #(#idents: <#types as Info<#l, #t>>::Context::default(),)* }
}
}
}
impl<#(#ol4,)* #(#ls,)* #(#ot,)* #(#ts: #bs,)* #(const #cs: #cts,)*> Info<#l, #t>
for #ident<#(#ls,)* #(#ts,)* #(#cs,)*> {
type Context = #mident::#cident<#(#ol5,)* #(#ls,)* #(#ts,)* #(#cs,)*>;
fn generate(ctx: &mut Self::Context, ts: &#l [#t]) -> Self {
Self {
#(#idents: <#types as Info<#l, #t>>::generate(&mut ctx.#idents, ts),)*
}
}
}
})
} else {
panic!("Can only derive 'Info' on structs");
}
}
#[proc_macro_derive(StrInfo)]
pub fn str_info(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
if let Data::Struct(ref data) = input.data {
let empty = data.fields.is_empty();
let ls = input.generics.params.iter().filter_map(|g| match g {
GenericParam::Lifetime(l) => Some(&l.lifetime), _ => None,
}).collect::<Vec<_>>();
let l = ls.first().map(|&l| l.clone()).unwrap_or_else(|| if empty {
Lifetime::new("'_", Span::call_site().into())
} else {
Lifetime::new("'a", Span::call_site().into())
});
let ol = (ls.is_empty() && !empty).then(|| &l);
let ol1 = ol.iter();
let ol2 = ol.iter();
let ol3 = ol.iter();
let ol4 = ol.iter();
let ol5 = ol.iter();
let ts = input.generics.params.iter().filter_map(|g| match g {
GenericParam::Type(t) => Some(&t.ident), _ => None,
}).collect::<Vec<_>>();
let bs = input.generics.params.iter().filter_map(|g| match g {
GenericParam::Type(t) => Some(&t.bounds), _ => None,
}).collect::<Vec<_>>();
let cs = input.generics.params.iter().filter_map(|g| match g {
GenericParam::Const(c) => Some(&c.ident), _ => None,
}).collect::<Vec<_>>();
let cts = input.generics.params.iter().filter_map(|g| match g {
GenericParam::Const(c) => Some(&c.ty), _ => None,
}).collect::<Vec<_>>();
let ident = &input.ident;
let cident = format_ident!("{}Ctx", ident);
let mident = format_ident!("{}_ctx", ident.to_string().to_lowercase());
let types = data.fields.iter().map(|t| &t.ty).collect::<Vec<_>>();
let idents = data.fields.iter().map(|i| &i.ident).collect::<Vec<_>>();
TokenStream::from(quote! {
mod #mident {
use super::*;
pub struct #cident<#(#ol1,)* #(#ls,)* #(#ts: #bs,)* #(const #cs: #cts,)*> {
#(pub(super) #idents: <#types as StrInfo<#l>>::Context,)*
}
impl<#(#ol2,)* #(#ls,)* #(#ts: #bs,)* #(const #cs: #cts,)*> Default
for #cident<#(#ol3,)* #(#ls,)* #(#ts,)* #(const #cs,)*> {
fn default() -> Self {
Self { #(#idents: <#types as StrInfo<#l>>::Context::default(),)* }
}
}
}
impl<#(#ol4,)* #(#ls,)* #(#ts: #bs,)* #(const #cs: #cts,)*> StrInfo<#l>
for #ident<#(#ls,)* #(#ts,)* #(#cs,)*> {
type Context = #mident::#cident<#(#ol5,)* #(#ls,)* #(#ts,)* #(#cs,)*>;
fn generate(ctx: &mut Self::Context, ts: &#l str) -> Self {
Self {
#(#idents: <#types as StrInfo<#l>>::generate(&mut ctx.#idents, ts),)*
}
}
}
})
} else {
panic!("Can only derive 'StrInfo' on structs");
}
}