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 let input = parse_macro_input!(input as DeriveInput);
14
15 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 TokenStream::from(expanded)
28}
29
30#[proc_macro_derive(CheckpointFunction)]
31pub fn derive_checkpoint_function(input: TokenStream) -> TokenStream {
32 let input = parse_macro_input!(input as DeriveInput);
34
35 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 TokenStream::from(expanded)
44}
45
46#[proc_macro_derive(Function)]
47pub fn derive_function(input: TokenStream) -> TokenStream {
48 let input = parse_macro_input!(input as DeriveInput);
50
51 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 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; let name = &sig.ident;
76 let inputs = &sig.inputs;
77 let body = &input.block;
78 let _attrs = &input.attrs;
79 let _vis = input.vis; 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 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 result.into()
144}