Skip to main content

radiantkit_macros/
lib.rs

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    // use proc_utils::*;
210    // res.pretty_print();
211
212    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    // use proc_utils::*;
363    // res.pretty_print();
364
365    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}