ferris_gc_proc_macro/
lib.rs

1use proc_macro::TokenStream;
2use std::borrow::{Borrow, BorrowMut};
3use quote::quote;
4use syn::{ReturnType, Type, Data, Fields};
5
6#[proc_macro_derive(Trace, attributes(unsafe_ignore_trace))]
7pub fn derive_trace(item: TokenStream) -> TokenStream {
8    let derive_input = syn::parse_macro_input!(item as syn::DeriveInput);
9
10    let ident = &derive_input.ident;
11    let data_type = &derive_input.data;
12    let trace_impl = match data_type {
13        Data::Struct(data_struct) => {
14            match &data_struct.fields {
15                Fields::Named(named_fields) => {
16                    let mut fields = Vec::new();
17                    for field in &named_fields.named {
18                        let attrs = &field.attrs;
19                        if !attrs.into_iter().any(|attr| attr.path.get_ident().unwrap() == "unsafe_ignore_trace") {
20                            let ident = &field.ident;
21                            fields.push(ident);
22                        }
23                    }
24                    quote! {
25                        impl Trace for #ident {
26                            fn is_root(&self) -> bool {
27                                unreachable!("is_root should never be called on user-defined type !!");
28                            }
29
30                            fn reset_root(&self) {
31                                #(self.#fields.reset_root();)*
32                            }
33
34                            fn trace(&self) {
35                                #(self.#fields.trace();)*
36                            }
37
38                            fn reset(&self) {
39                                #(self.#fields.reset();)*
40                            }
41
42                            fn is_traceable(&self) -> bool {
43                                unreachable!("is_traceable should never be called on user-defined type !!");
44                            }
45                        }
46                    }
47                },
48                Fields::Unnamed(unnamed_fields) => {
49                    let mut fields = Vec::new();
50                    let mut idx = 0;
51                    for field in &unnamed_fields.unnamed {
52                        let attrs = &field.attrs;
53                        if !attrs.into_iter().any(|attr| attr.path.get_ident().unwrap() == "unsafe_ignore_trace") {
54                            fields.push(idx);
55                        }
56                        idx += 1;
57                    }
58                    quote! {
59                        impl Trace for #ident {
60                            fn is_root(&self) -> bool {
61                                unreachable!("is_root should never be called on user-defined type !!");
62                            }
63
64                            fn reset_root(&self) {
65                                #(self.#fields.reset_root();)*
66                            }
67
68                            fn trace(&self) {
69                                #(self.#fields.trace();)*
70                            }
71
72                            fn reset(&self) {
73                                #(self.#fields.reset();)*
74                            }
75
76                            fn is_traceable(&self) -> bool {
77                                unreachable!("is_traceable should never be called on user-defined type !!");
78                            }
79                        }
80                    }
81                },
82                Fields::Unit => {
83                    panic!("Unit type is not supported !!");
84                },
85            }
86        },
87        Data::Enum(data_enum) => {
88            panic!("Enum type is not supported !!");
89        },
90        Data::Union(data_union) => {
91            panic!("Union type is not supported !!");
92        },
93    };
94
95    let print_tokens = Into::<TokenStream>::into(trace_impl.clone());
96    println!("Result Trace Impl is {}", print_tokens.to_string());
97    trace_impl.into()
98}
99
100#[proc_macro_derive(Finalize)]
101pub fn derive_finalize(item: TokenStream) -> TokenStream {
102    let derive_input = syn::parse_macro_input!(item as syn::DeriveInput);
103
104    let ident = &derive_input.ident;
105    let finalizer_impl = quote! {
106        impl Finalize for #ident {
107            fn finalize(&self) {
108            }
109        }
110    };
111
112    let print_tokens = Into::<TokenStream>::into(finalizer_impl.clone());
113    println!("Result Finalizer Impl is {}", print_tokens.to_string());
114    finalizer_impl.into()
115}
116
117#[proc_macro_attribute]
118pub fn ferris_gc_main(attrs: TokenStream, item: TokenStream) -> TokenStream {
119    let input = syn::parse_macro_input!(item as syn::ItemFn);
120    let attr_args = syn::parse_macro_input!(attrs as syn::AttributeArgs);
121
122    let sig = &input.sig;
123    let vis = input.vis;
124    let name = &input.sig.ident;
125    if name != "main" {
126        panic!("#[ferris_gc_main] is applied only for main function")
127    }
128    let mut args = Vec::new();
129    for arg in &input.sig.inputs {
130        args.push(arg);
131    }
132    let ret = match &input.sig.output {
133        ReturnType::Default => {
134            quote! {
135            }
136        },
137        ReturnType::Type(arrow, box_type) => {
138            quote! {
139                -> #box_type
140            }
141        }
142    };
143    let body = &input.block;
144    let attrs = &input.attrs;
145
146    let res_fun = quote! {
147        #(#attrs)*
148        #vis fn #name (#(#args),*) #ret {
149            // Should be added proper closing background threads
150            let cleanup = ApplicationCleanup;
151            {
152                #body
153            }
154        }
155    };
156
157    let print_tokens = Into::<TokenStream>::into(res_fun.clone());
158    println!("Result Function is {}", print_tokens.to_string());
159    res_fun.into()
160}