rlink_derive/
lib.rs

1#[macro_use]
2extern crate quote;
3#[macro_use]
4extern crate syn;
5
6use syn::DeriveInput;
7
8use proc_macro::TokenStream;
9
10#[proc_macro_derive(NamedFunction)]
11pub fn derive_named_function(input: TokenStream) -> TokenStream {
12    // Parse the input tokens into a syntax tree
13    let input = parse_macro_input!(input as DeriveInput);
14
15    // Build the output, possibly using quasi-quotation
16    let name = &input.ident;
17    let (im, ty, wh) = input.generics.split_for_impl();
18    let expanded = quote! {
19        impl #im rlink::core::function::NamedFunction for #name #ty #wh {
20            fn name(&self) -> &str {
21                stringify!(#name)
22            }
23        }
24    };
25
26    // Hand the output tokens back to the compiler
27    TokenStream::from(expanded)
28}
29
30#[proc_macro_derive(CheckpointFunction)]
31pub fn derive_checkpoint_function(input: TokenStream) -> TokenStream {
32    // Parse the input tokens into a syntax tree
33    let input = parse_macro_input!(input as DeriveInput);
34
35    // Build the output, possibly using quasi-quotation
36    let name = &input.ident;
37    let (im, ty, wh) = input.generics.split_for_impl();
38    let expanded = quote! {
39        impl #im rlink::core::checkpoint::CheckpointFunction for #name #ty #wh {}
40    };
41
42    // Hand the output tokens back to the compiler
43    TokenStream::from(expanded)
44}
45
46#[proc_macro_derive(Function)]
47pub fn derive_function(input: TokenStream) -> TokenStream {
48    // Parse the input tokens into a syntax tree
49    let input = parse_macro_input!(input as DeriveInput);
50
51    // Build the output, possibly using quasi-quotation
52    let name = &input.ident;
53    let (im, ty, wh) = input.generics.split_for_impl();
54    let expanded = quote! {
55        impl #im rlink::core::function::NamedFunction for #name #ty #wh {
56            fn name(&self) -> &str {
57                stringify!(#name)
58            }
59        }
60
61        impl #im rlink::core::checkpoint::CheckpointFunction for #name #ty #wh {}
62    };
63
64    // Hand the output tokens back to the compiler
65    TokenStream::from(expanded)
66}
67
68#[proc_macro_attribute]
69#[cfg(not(test))]
70pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
71    let mut input = syn::parse_macro_input!(item as syn::ItemFn);
72    let args = syn::parse_macro_input!(args as syn::AttributeArgs);
73
74    let sig = &mut input.sig; // eg: struct Name, function sig
75    let name = &sig.ident;
76    let inputs = &sig.inputs;
77    let body = &input.block;
78    let _attrs = &input.attrs;
79    let _vis = input.vis; // eg: pub, pub(crate), etc...
80
81    if sig.asyncness.is_some() {
82        let msg = "the async keyword is unsupported from the function declaration";
83        return syn::Error::new_spanned(sig.fn_token, msg)
84            .to_compile_error()
85            .into();
86    } else if name != "main" {
87        let msg = "the function name must be `main`";
88        return syn::Error::new_spanned(&sig.inputs, msg)
89            .to_compile_error()
90            .into();
91    } else if inputs.is_empty() {
92        let msg = "the main function accept arguments";
93        return syn::Error::new_spanned(&sig.inputs, msg)
94            .to_compile_error()
95            .into();
96    }
97
98    // if args.len() != 1 {
99    //     let msg = "the main function accept arguments";
100    //     return syn::Error::new_spanned(&args., msg)
101    //         .to_compile_error()
102    //         .into();
103    // }
104
105    let arg0 = &args[0];
106    let stream_fn = if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = arg0 {
107        let ident = path.get_ident();
108        if ident.is_none() {
109            let msg = "Must have specified ident";
110            return syn::Error::new_spanned(path, msg).to_compile_error().into();
111        }
112
113        ident.unwrap()
114    } else {
115        let msg = "Must have specified ident..";
116        return syn::Error::new_spanned(arg0, msg).to_compile_error().into();
117    };
118
119    let result = quote! {
120        #[derive(Clone, Debug)]
121        pub struct GenStreamJob {}
122
123        impl rlink::core::env::StreamJob for GenStreamJob {
124            fn prepare_properties(&self, properties: &mut Properties) {
125                #body
126            }
127
128            fn build_stream(
129                &self,
130                properties: &Properties,
131                env: &StreamExecutionEnvironment,
132            ) -> SinkStream {
133                #stream_fn(properties, env)
134            }
135        }
136
137        fn main() {
138            rlink::core::env::execute("job_name", GenStreamJob{});
139        }
140    };
141
142    // println!("{}", result.to_string());
143    result.into()
144}