1use proc_macro2::{Ident, Span, TokenStream};
2use quote::quote;
3use syn::{
4 parenthesized, parse::Parse, DeriveInput, Field, FieldsNamed, FieldsUnnamed, LitStr, Token,
5};
6
7#[proc_macro_derive(LiveMod, attributes(livemod))]
8pub fn livemod_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
9 let ast: DeriveInput = syn::parse(input).unwrap();
10
11 match ast.data {
12 syn::Data::Struct(st) => {
13 let struct_name = ast.ident;
14 let (
15 FieldsDerive {
16 idents,
17 default_values: _,
18 representations,
19 get_named_values,
20 get_selves,
21 },
22 named,
23 ) = match st.fields {
24 syn::Fields::Named(fields) => (derive_fields_named(fields), true),
25 syn::Fields::Unnamed(fields) => (derive_fields_unnamed(fields), false),
26 syn::Fields::Unit => {
27 let gen = quote! {
28 compile_error!("Derive not supported on unit struct")
29 };
30 return gen.into();
31 }
32 };
33
34 let self_pattern = if named {
35 quote! { Self { #(#idents),* } }
36 } else {
37 quote! { Self ( #(#idents),* ) }
38 };
39
40 let gen = quote! {
41 #[automatically_derived]
42 impl ::livemod::LiveMod for #struct_name {
43 fn repr_default(&self, target: ::livemod::ActionTarget) -> ::livemod::Namespaced<::livemod::Repr> {
44 let #self_pattern = self;
45 if let Some((field, field_target)) = target.strip_one_field() {
46 match field {
47 #(#get_named_values as &dyn ::livemod::LiveMod,)*
48 _ => panic!("Unexpected value name!"),
49 }.repr_default(field_target)
50 } else {
51 ::livemod::Namespaced::basic_structure_repr(
52 stringify!(#struct_name),
53 &[
54 #(#representations),*
55 ],
56 )
57 }
58 }
59
60 fn accept(&mut self, target: ::livemod::ActionTarget, value: ::livemod::Parameter<::livemod::Value>) -> bool {
61 let #self_pattern = self;
62 if let Some((field, field_target)) = target.strip_one_field() {
63 match field {
64 #(#get_named_values as &mut dyn ::livemod::LiveMod,)*
65 _ => panic!("Unexpected target!"),
66 }.accept(field_target, value)
67 } else {
68 panic!("Unexpected value!")
69 }
70 }
71
72 fn get_self(&self, target: ::livemod::ActionTarget) -> ::livemod::Parameter<::livemod::Value> {
73 let #self_pattern = self;
74 if let Some((field, field_target)) = target.strip_one_field() {
75 match field {
76 #(#get_named_values as &dyn ::livemod::LiveMod,)*
77 _ => panic!("Unexpected value name!"),
78 }.get_self(field_target)
79 } else {
80 ::livemod::Parameter::Namespaced(::livemod::Namespaced::basic_structure_value(&[
81 #(#get_selves),*
82 ]))
83 }
84 }
85 }
86 };
87 gen.into()
88 }
89 syn::Data::Enum(en) => {
90 let enum_name = ast.ident;
91
92 let mut variant_names = vec![];
93 let mut variant_fields = vec![];
94 let mut variant_get_named_values = vec![];
95 let mut variant_get_named_values_mut = vec![];
96 let mut variant_defaults = vec![];
97 let mut variant_get_selves = vec![];
98
99 for variant in en.variants {
100 let variant_name = variant.ident;
101 let variant_string = variant_name.to_string();
102 variant_names.push(variant_string.clone());
103 match variant.fields {
104 syn::Fields::Named(fields) => {
105 let FieldsDerive {
106 idents,
107 default_values,
108 representations,
109 get_named_values,
110 get_selves,
111 } = derive_fields_named(fields);
112 let self_pattern = quote! {
113 Self::#variant_name { #(#idents),* }
114 };
115
116 variant_fields
117 .push(quote! { #self_pattern => vec![#(#representations),*] });
118 variant_get_named_values.push(quote! { #self_pattern => match name { #(#get_named_values as &dyn ::livemod::LiveMod,)* _ => panic!("Unexpected value name!") } });
119 variant_get_named_values_mut.push(quote! { #self_pattern => match name { #(#get_named_values as &mut dyn ::livemod::LiveMod,)* _ => panic!("Unexpected value name!") } });
120 variant_defaults.push(quote! { #variant_string => Self::#variant_name { #(#idents: #default_values),* } });
121 variant_get_selves.push(quote! {
122 #self_pattern => ::livemod::Namespaced::new(
123 vec![String::from("livemod"), String::from("enum")],
124 <_ as ::std::iter::FromIterator<_>>::from_iter(::std::array::IntoIter::new([
125 (String::from("variant"), Parameter::String(String::from(#variant_string))),
126 (String::from("current"), Parameter::Namespaced(::livemod::Namespaced::fields_value(&[#(#get_selves),*]))),
127 ]))
128 )
129 });
130 }
131 syn::Fields::Unnamed(fields) => {
132 let FieldsDerive {
133 idents,
134 default_values,
135 representations,
136 get_named_values,
137 get_selves,
138 } = derive_fields_unnamed(fields);
139 let self_pattern = quote! {
140 Self::#variant_name ( #(#idents),* )
141 };
142
143 variant_fields
144 .push(quote! { #self_pattern => vec![#(#representations),*] });
145 variant_get_named_values.push(quote! { #self_pattern => match name { #(#get_named_values as &dyn ::livemod::LiveMod,)* _ => panic!("Unexpected value name!") } });
146 variant_get_named_values_mut.push(quote! { #self_pattern => match name { #(#get_named_values as &mut dyn ::livemod::LiveMod,)* _ => panic!("Unexpected value name!") } });
147 variant_defaults.push(quote! { #variant_string => Self::#variant_name ( #(#default_values),* ) });
148 variant_get_selves.push(quote! {
149 #self_pattern => ::livemod::Namespaced::new(
150 vec![String::from("livemod"), String::from("enum")],
151 <_ as ::std::iter::FromIterator<_>>::from_iter(::std::array::IntoIter::new([
152 (String::from("variant"), Parameter::String(String::from(#variant_string))),
153 (String::from("current"), Parameter::Namespaced(::livemod::Namespaced::fields_value(&[#(#get_selves),*]))),
154 ]))
155 )
156 });
157 }
158 syn::Fields::Unit => {
159 variant_fields.push(quote! { Self::#variant_name => vec![] });
160 variant_get_named_values.push(
161 quote! { Self::#variant_name => panic!("Unexpected value name!") },
162 );
163 variant_get_named_values_mut.push(
164 quote! { Self::#variant_name => panic!("Unexpected value name!") },
165 );
166 variant_defaults.push(quote! { #variant_string => Self::#variant_name });
167 variant_get_selves.push(quote! { Self::#variant_name => ::livemod::Namespaced::new(vec![String::from("livemod"), String::from("enum")], <_ as ::std::iter::FromIterator<_>>::from_iter(::std::array::IntoIter::new([(String::from("variant"), Parameter::String(String::from(#variant_string)))]))) });
168 }
169 }
170 }
171
172 let gen = quote! {
173 #[automatically_derived]
174 impl ::livemod::LiveMod for #enum_name {
175 fn repr_default(&self, target: ::livemod::ActionTarget) -> ::livemod::Namespaced<::livemod::Repr> {
176 if let Some((name, field_target)) = target.strip_one_field() {
177 match self {
178 #(#variant_get_named_values ,)*
179 }.repr_default(field_target)
180 } else {
181 ::livemod::Namespaced::new(
182 vec![
183 String::from("livemod"),
184 String::from("enum"),
185 ],
186 <_ as ::std::iter::FromIterator<_>>::from_iter(::std::array::IntoIter::new([
187 (String::from("name"), Parameter::String(String::from(stringify!(#enum_name)))),
188 (
189 String::from("variants"),
190 Parameter::Namespaced(Namespaced::new(
191 vec![String::from("livemod"), String::from("variants")],
192 <_ as ::std::iter::FromIterator<_>>::from_iter(
193 ::std::array::IntoIter::new([
194 #(#variant_names),*
195 ])
196 .enumerate()
197 .map(|(i, variant_name)| {
198 (i.to_string(), Parameter::String(variant_name.to_string()))
199 })
200 ),
201 )),
202 ),
203 (
204 String::from("current"),
205 Parameter::Namespaced(Namespaced::new(
206 vec![String::from("livemod"), String::from("fields")],
207 <_ as ::std::iter::FromIterator<_>>::from_iter(match self {
209 #(#variant_fields ,)*
210 }.into_iter().map(|(s, n)| (s, ::livemod::Parameter::Namespaced(n))))
211 )),
212 )
213 ]))
214 )
215 }
216 }
217
218 fn accept(&mut self, target: ::livemod::ActionTarget, value: ::livemod::Parameter<::livemod::Value>) -> bool {
219 if let Some((name, field_target)) = target.strip_one_field() {
220 if name == "variant" {
221 let variant_name = value.as_string().unwrap();
222 *self = match variant_name.as_str() {
223 #(#variant_defaults ,)*
224 name => panic!("Unknown variant name: {}", name)
225 };
226 true
227 } else {
228 if let Some((name, field_target)) = field_target.strip_one_field() {
229 match self {
230 #(#variant_get_named_values_mut ,)*
231 }.accept(field_target, value)
232 } else {
233 unimplemented!()
234 }
235 }
236 } else {
237 unimplemented!()
238 }
239 }
240
241 fn get_self(&self, target: ActionTarget) -> ::livemod::Parameter<::livemod::Value> {
242 if let Some((name, field_target)) = target.strip_one_field() {
243 match self {
244 #(#variant_get_named_values ,)*
245 }.get_self(field_target)
246 } else {
247 ::livemod::Parameter::Namespaced(match self {
248 #(#variant_get_selves ,)*
249 })
250 }
251 }
252 }
253 };
254 gen.into()
255 }
256 syn::Data::Union(_) => {
257 let gen = quote! {
258 compile_error!("Derive not supported on union")
259 };
260 gen.into()
261 }
262 }
263}
264
265struct FieldsDerive {
266 idents: Vec<Ident>,
267 default_values: Vec<TokenStream>,
268 representations: Vec<TokenStream>,
269 get_named_values: Vec<TokenStream>,
270 get_selves: Vec<TokenStream>,
271}
272
273struct FieldDerive {
274 ident: Ident,
275 default_value: TokenStream,
276 representation: Option<TokenStream>,
277 get_named_value: Option<TokenStream>,
278 get_self: Option<TokenStream>,
279}
280
281fn derive_fields_named(fields: FieldsNamed) -> FieldsDerive {
282 let iter = fields.named.into_iter().map(|field| {
283 let ident = field.ident.clone().unwrap();
284 let name = ident.to_string();
285 derive_field(ident, name, field)
286 });
287
288 let mut gen = FieldsDerive {
289 idents: Vec::new(),
290 default_values: Vec::new(),
291 representations: Vec::new(),
292 get_named_values: Vec::new(),
293 get_selves: Vec::new(),
294 };
295
296 for field in iter {
297 gen.idents.push(field.ident);
298 gen.default_values.push(field.default_value);
299 gen.representations.extend(field.representation);
300 gen.get_named_values.extend(field.get_named_value);
301 gen.get_selves.extend(field.get_self);
302 }
303
304 gen
305}
306
307fn derive_fields_unnamed(fields: FieldsUnnamed) -> FieldsDerive {
308 let iter = fields.unnamed.into_iter().enumerate().map(|(i, field)| {
309 let ident = Ident::new(&format!("__{}", i), Span::call_site());
310 let name = i.to_string();
311 derive_field(ident, name, field)
312 });
313
314 let mut gen = FieldsDerive {
315 idents: Vec::new(),
316 default_values: Vec::new(),
317 representations: Vec::new(),
318 get_named_values: Vec::new(),
319 get_selves: Vec::new(),
320 };
321
322 for field in iter {
323 gen.idents.push(field.ident);
324 gen.default_values.push(field.default_value);
325 gen.representations.extend(field.representation);
326 gen.get_named_values.extend(field.get_named_value);
327 gen.get_selves.extend(field.get_self);
328 }
329
330 gen
331}
332
333fn derive_field(ident: Ident, default_name: String, field: Field) -> FieldDerive {
334 let attrs = match field
335 .attrs
336 .into_iter()
337 .filter_map(|attr| {
338 if attr.path.is_ident("livemod") {
339 Some(syn::parse2(attr.tokens))
340 } else {
341 None
342 }
343 })
344 .collect::<Result<Vec<_>, _>>()
345 {
346 Ok(attrs) => attrs,
347 Err(error) => {
348 return FieldDerive {
349 ident,
350 default_value: error.to_compile_error(),
351 representation: None,
352 get_named_value: None,
353 get_self: None,
354 };
355 }
356 };
357
358 let default_value = if let Some(default) = attrs.iter().find_map(|attr| match attr {
359 Attr::Default(ts) => Some(ts),
360 _ => None,
361 }) {
362 default.clone()
363 } else {
364 quote! { ::std::default::Default::default() }
365 };
366
367 let name = if let Some(name) = attrs.iter().find_map(|attr| match attr {
368 Attr::Rename(name) => Some(name),
369 _ => None,
370 }) {
371 name.clone()
372 } else {
373 default_name
374 };
375
376 let (representation, get_named_value, get_self) = if attrs
377 .iter()
378 .any(|attr| matches!(attr, Attr::Skip))
379 {
380 (None, None, None)
381 } else {
382 let default_repr = quote! { ::livemod::DefaultRepr };
383 let repr_struct = attrs
384 .iter()
385 .find_map(|attr| match attr {
386 Attr::Repr(ts) => Some(ts),
387 _ => None,
388 })
389 .unwrap_or(&default_repr);
390 let representation = quote! {
391 (#name.to_owned(), ::livemod::LiveModRepr::repr(&#repr_struct, #ident))
392 };
393
394 let get_named_value = quote! { #name => #ident };
395 let get_self = quote! { (#name.to_owned(), ::livemod::LiveMod::get_self(#ident, ::livemod::ActionTarget::This)) };
396 (Some(representation), Some(get_named_value), Some(get_self))
397 };
398
399 FieldDerive {
400 ident,
401 default_value,
402 representation,
403 get_named_value,
404 get_self,
405 }
406}
407
408enum Attr {
409 Skip,
410 Rename(String),
411 Repr(TokenStream),
412 Default(TokenStream),
413}
414
415impl Parse for Attr {
416 fn parse(direct_input: syn::parse::ParseStream) -> syn::Result<Self> {
417 let input;
418 parenthesized!(input in direct_input);
419 let attr_type: Ident = input.parse()?;
420 if attr_type == "skip" {
421 if !input.is_empty() {
422 return Err(input.error("Expected end of attribute content"));
423 }
424 Ok(Attr::Skip)
425 } else if attr_type == "rename" {
426 input.parse::<Token![=]>()?;
427 let new_name: LitStr = input.parse()?;
428 Ok(Attr::Rename(new_name.value()))
429 } else if attr_type == "repr" {
430 input.parse::<Token![=]>()?;
431 Ok(Attr::Repr(input.parse()?))
432 } else if attr_type == "default" {
433 input.parse::<Token![=]>()?;
434 Ok(Attr::Default(input.parse()?))
435 } else {
436 Err(syn::Error::new(
437 attr_type.span(),
438 "Unrecognised attribute tag",
439 ))
440 }
441 }
442}