cloud_macro/
lib.rs

1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{Error, FnArg, ItemFn, PatType, Pat, PatIdent};
4
5#[proc_macro_attribute]
6pub fn cloud(_: TokenStream, input: TokenStream) -> TokenStream {
7    // Parse ast from token stream
8    let ast = syn::parse::<ItemFn>(input).expect("Place this attribute above a function");
9
10    // Signature and output type
11    let name = ast.sig.ident;
12    let output = ast.sig.output;
13    let stub_name = format_ident!("{name}_stub");
14
15    // Stub
16    let body = ast.block.stmts;
17    let stub = match ast.sig.inputs.first() {
18        Some(FnArg::Typed(PatType { pat, ty, .. })) => match &**pat {
19            Pat::Ident(PatIdent { mutability, ident, ..}) => quote! {
20                let #ident = ::cloud_lib::rmp_serde::from_slice::<#ty>(__input_bytes).unwrap();
21
22                // Actual code
23                fn #stub_name(#mutability #ident: #ty) #output {
24                    #(#body);*
25                }
26                let output = #stub_name(#ident);
27
28                // Serialize output
29                let __output_bytes = ::cloud_lib::rmp_serde::to_vec_named(&output).unwrap().leak();
30                ::std::boxed::Box::new(::cloud_lib::CloudSlice {
31                    len: __output_bytes.len(),
32                    ptr: __output_bytes.as_mut_ptr(),
33                })
34            },
35            _ => Error::new(name.span(), "expected ident").to_compile_error(),
36        },
37        _ => Error::new(name.span(), "expected one argument").to_compile_error(),
38    };
39
40    quote! {
41        #[no_mangle]
42        fn #name(ptr: usize) -> ::std::boxed::Box<::cloud_lib::CloudSlice> {
43            // Deserialize input
44            let __input_bytes = unsafe {
45                let len = *(ptr as *const usize);
46                let data = (ptr + 4) as *mut u8;
47                ::std::slice::from_raw_parts(data, len)
48            };
49
50            #stub
51        }
52    }
53    .into()
54}