1use macro_magic::import_tokens_attr;
2use proc_macro::TokenStream;
3use proc_macro2::TokenStream as TokenStream2;
4use quote::{quote, ToTokens};
5
6fn derive_tessellatable_internal(item: TokenStream2) -> syn::Result<TokenStream2> {
7 let item = syn::parse2::<syn::ItemEnum>(item)?;
8
9 let name = item.ident.clone();
10 let node_names = item
11 .variants
12 .iter()
13 .map(|variant| variant.ident.clone())
14 .collect::<Vec<_>>();
15
16 let res = quote! {
17 impl RadiantTessellatable for #name {
18 fn attach(&mut self, screen_descriptor: &ScreenDescriptor) {
19 match self {
20 #(
21 #name::#node_names(node) => node.attach(screen_descriptor),
22 )*
23 }
24 }
25
26 fn detach(&mut self) {
27 match self {
28 #(
29 #name::#node_names(node) => node.detach(),
30 )*
31 }
32 }
33
34 fn set_needs_tessellation(&mut self) {
35 match self {
36 #(
37 #name::#node_names(node) => node.set_needs_tessellation(),
38 )*
39 }
40 }
41
42 fn tessellate(
43 &mut self,
44 selection: bool,
45 screen_descriptor: &ScreenDescriptor,
46 fonts_manager: &epaint::text::Fonts,
47 ) -> Vec<ClippedPrimitive> {
48 match self {
49 #(
50 #name::#node_names(node) => node.tessellate(selection, screen_descriptor, fonts_manager),
51 )*
52 }
53 }
54 }
55 };
56 Ok(res)
57}
58
59fn derive_node_internal(item: TokenStream2) -> syn::Result<TokenStream2> {
60 let item = syn::parse2::<syn::ItemEnum>(item)?;
61
62 let name = item.ident.clone();
63 let node_names = item
64 .variants
65 .iter()
66 .map(|variant| variant.ident.clone())
67 .collect::<Vec<_>>();
68 let nodes = item.variants.iter().map(|variant| {
69 let fields = variant.fields.iter();
70 quote! {
71 #(#fields)*
72 }
73 });
74
75 let res = quote! {
76 impl RadiantNode for #name {
77 fn get_id(&self) -> u64 {
78 match self {
79 #(
80 #name::#node_names(node) => node.get_id(),
81 )*
82 }
83 }
84
85 fn set_id(&mut self, id: u64) {
86 match self {
87 #(
88 #name::#node_names(node) => node.set_id(id),
89 )*
90 }
91 }
92
93 fn get_bounding_rect(&self) -> [f32; 4] {
94 match self {
95 #(
96 #name::#node_names(node) => node.get_bounding_rect(),
97 )*
98 }
99 }
100 }
101
102 #(
103 impl From<#nodes> for #name {
104 fn from(node: #nodes) -> Self {
105 Self::#node_names(node)
106 }
107 }
108 )*
109 };
110 Ok(res)
111}
112
113fn derive_component_provider_internal(item: TokenStream2) -> syn::Result<TokenStream2> {
114 let item = syn::parse2::<syn::ItemEnum>(item)?;
115
116 let name = item.ident.clone();
117 let node_names = item
118 .variants
119 .iter()
120 .map(|variant| variant.ident.clone())
121 .collect::<Vec<_>>();
122
123 let res = quote! {
124 impl RadiantComponentProvider for #name {
125 fn get_component<T: RadiantComponent + 'static>(&self) -> Option<&T> {
126 match self {
127 #(
128 #name::#node_names(node) => node.get_component(),
129 )*
130 }
131 }
132
133 fn get_component_mut<T: RadiantComponent + 'static>(&mut self) -> Option<&mut T> {
134 match self {
135 #(
136 #name::#node_names(node) => node.get_component_mut(),
137 )*
138 }
139 }
140 }
141 };
142 Ok(res)
143}
144
145fn combine_enum_internal(
146 attr: TokenStream2,
147 item: TokenStream2,
148 foreign_path: syn::Path,
149) -> syn::Result<TokenStream2> {
150 let mut local_enum = syn::parse2::<syn::ItemEnum>(item.clone())?;
151 let local_name = local_enum.ident.clone();
152
153 let foreign_enum = syn::parse2::<syn::ItemEnum>(attr)?;
154 let foreign_variants = foreign_enum
155 .variants
156 .iter()
157 .map(|variant| variant.ident.clone())
158 .collect::<Vec<_>>();
159 let foreign_args = foreign_enum
160 .variants
161 .iter()
162 .map(|variant| {
163 variant
164 .fields
165 .iter()
166 .map(|field| field.ident.clone())
167 .collect::<Vec<_>>()
168 })
169 .collect::<Vec<_>>();
170
171 foreign_enum.variants.iter().for_each(|variant| {
172 if local_enum
173 .variants
174 .iter()
175 .any(|local_variant| local_variant.ident == variant.ident)
176 {
177 return;
178 }
179 local_enum.variants.push(variant.clone());
180 });
181
182 let res = quote! {
183 #local_enum
184
185 impl From<#foreign_path> for #local_name {
186 fn from(foreign: #foreign_path) -> Self {
187 match foreign {
188 #(
189 #foreign_path::#foreign_variants { #(#foreign_args,)* } => Self::#foreign_variants { #(#foreign_args,)* },
190 )*
191 }
192 }
193 }
194
195 impl TryInto<#foreign_path> for #local_name {
196 type Error = ();
197
198 fn try_into(self) -> Result<#foreign_path, Self::Error> {
199 match self {
200 #(
201 Self::#foreign_variants { #(#foreign_args,)* } => Ok(#foreign_path::#foreign_variants { #(#foreign_args,)* }),
202 )*
203 _ => Err(()),
204 }
205 }
206 }
207 };
208
209 Ok(res)
213}
214
215fn nested_message_internal(item: TokenStream2) -> syn::Result<TokenStream2> {
216 let item = syn::parse2::<syn::ItemEnum>(item)?;
217
218 let name = item.ident.clone();
219 let message_names = item
220 .variants
221 .iter()
222 .map(|variant| variant.ident.clone())
223 .collect::<Vec<_>>();
224 let messages = item
225 .variants
226 .iter()
227 .map(|variant| {
228 let fields = variant.fields.iter();
229 quote! {
230 #(#fields)*
231 }
232 })
233 .collect::<Vec<_>>();
234
235 let res = quote! {
236 #item
237
238 #(
239 impl From<#messages> for #name {
240 fn from(message: #messages) -> Self {
241 Self::#message_names(message)
242 }
243 }
244 )*
245
246 #(
247 impl TryFrom<#name> for #messages {
248 type Error = ();
249
250 fn try_from(message: #name) -> Result<Self, Self::Error> {
251 match message {
252 #name::#message_names(message) => Ok(message),
253 _ => Err(()),
254 }
255 }
256 }
257 )*
258 };
259 Ok(res)
260}
261
262fn combine_response_internal(
263 attr: TokenStream2,
264 item: TokenStream2,
265 foreign_path: syn::Path,
266) -> syn::Result<TokenStream2> {
267 let mut m_replacement: Option<TokenStream2> = None;
268 let mut n_replacement: Option<TokenStream2> = None;
269
270 let path = foreign_path.segments.last().unwrap().clone();
271 if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
272 args, ..
273 }) = path.arguments
274 {
275 let mut iter = args.iter();
276 if let Some(arg1) = iter.next() {
277 if let syn::GenericArgument::Type(ty) = arg1 {
278 m_replacement = Some(quote!(#ty));
279 }
280 }
281 if let Some(arg2) = iter.next() {
282 if let syn::GenericArgument::Type(ty) = arg2 {
283 n_replacement = Some(quote!(#ty));
284 }
285 }
286 }
287
288 let mut local_enum = syn::parse2::<syn::ItemEnum>(item.clone())?;
289 let local_name = local_enum.ident.clone();
290
291 let foreign_enum = syn::parse2::<syn::ItemEnum>(attr)?;
292 let foreign_name = foreign_enum.ident.clone();
293
294 let foreign_variants = foreign_enum
295 .variants
296 .iter()
297 .map(|variant| variant.ident.clone())
298 .collect::<Vec<_>>();
299
300 let foreign_args = foreign_enum
301 .variants
302 .iter()
303 .map(|variant| {
304 variant
305 .fields
306 .iter()
307 .map(|field| field.ident.clone())
308 .collect::<Vec<_>>()
309 })
310 .collect::<Vec<_>>();
311
312 foreign_enum.variants.iter().for_each(|variant| {
313 if local_enum
314 .variants
315 .iter()
316 .any(|local_variant| local_variant.ident == variant.ident)
317 {
318 return;
319 }
320 let mut variant = variant.clone();
321 for field in variant.fields.iter_mut() {
322 match &(field.ty.to_token_stream().to_string())[..] {
323 "M" => {
324 field.ty = syn::parse2::<syn::Type>(quote! { #m_replacement }).unwrap();
325 }
326 "N" => {
327 field.ty = syn::parse2::<syn::Type>(quote! { #n_replacement }).unwrap();
328 }
329 _ => {}
330 }
331 }
332 local_enum.variants.push(variant);
333 });
334
335 let res = quote! {
336 #local_enum
337
338 impl From<#foreign_path> for #local_name {
339 fn from(response: #foreign_path) -> Self {
340 match response {
341 #(
342 #foreign_name::#foreign_variants { #(#foreign_args,)* } => Self::#foreign_variants { #(#foreign_args,)* },
343 )*
344 }
345 }
346 }
347
348 impl TryInto<#foreign_path> for #local_name {
349 type Error = ();
350
351 fn try_into(self) -> Result<#foreign_path, Self::Error> {
352 match self {
353 #(
354 Self::#foreign_variants { #(#foreign_args,)* } => Ok(#foreign_name::#foreign_variants { #(#foreign_args,)* }),
355 )*
356 _ => Err(()),
357 }
358 }
359 }
360 };
361
362 Ok(res)
366}
367
368#[proc_macro_derive(RadiantTessellatable)]
369pub fn derive_tessellatable(item: TokenStream) -> TokenStream {
370 let res = match derive_tessellatable_internal(item.into()) {
371 Ok(res) => res,
372 Err(err) => err.to_compile_error(),
373 };
374 res.into()
375}
376
377#[proc_macro_derive(RadiantNode)]
378pub fn derive_node(item: TokenStream) -> TokenStream {
379 let res = match derive_node_internal(item.into()) {
380 Ok(res) => res,
381 Err(err) => err.to_compile_error(),
382 };
383 res.into()
384}
385
386#[proc_macro_derive(RadiantComponentProvider)]
387pub fn derive_component_provider(item: TokenStream) -> TokenStream {
388 let res = match derive_component_provider_internal(item.into()) {
389 Ok(res) => res,
390 Err(err) => err.to_compile_error(),
391 };
392 res.into()
393}
394
395#[import_tokens_attr]
396#[proc_macro_attribute]
397pub fn combine_enum(attr: TokenStream, item: TokenStream) -> TokenStream {
398 let foreign_path = syn::parse::<syn::Path>(__source_path).unwrap();
399 let res = match combine_enum_internal(attr.into(), item.into(), foreign_path) {
400 Ok(res) => res,
401 Err(err) => err.to_compile_error(),
402 };
403 res.into()
404}
405
406#[proc_macro_attribute]
407pub fn nested_message(_attr: TokenStream, item: TokenStream) -> TokenStream {
408 let res = match nested_message_internal(item.into()) {
409 Ok(res) => res,
410 Err(err) => err.to_compile_error(),
411 };
412 res.into()
413}
414
415#[import_tokens_attr]
416#[proc_macro_attribute]
417pub fn combine_response(attr: TokenStream, item: TokenStream) -> TokenStream {
418 let foreign_path = syn::parse::<syn::Path>(__source_path).unwrap();
419 let res = match combine_response_internal(attr.into(), item.into(), foreign_path) {
420 Ok(res) => res,
421 Err(err) => err.to_compile_error(),
422 };
423 res.into()
424}