edgedb_sdk_macros/
lib.rs

1use proc_macro::TokenStream;
2use proc_macro_error::emit_error;
3use quote::quote;
4
5/// Register web handler
6#[proc_macro_error::proc_macro_error]
7#[proc_macro_attribute]
8pub fn web_handler(_attr: TokenStream, item: TokenStream) -> TokenStream {
9    let input = syn::parse_macro_input!(item as syn::ItemFn);
10    let func_name = &input.sig.ident;
11    let hook_name = quote::format_ident!(
12        "_edgedb_sdk_init_web_handler_{}", func_name);
13    quote! {
14        #input
15
16        #[export_name = stringify!(#hook_name)]
17        extern fn #hook_name() {
18            ::edgedb_sdk::web::register_handler(#func_name);
19        }
20
21    }.into()
22}
23
24/// Mark function to run at wasm initialization
25///
26/// In Rust it's uncommon to have init hooks. For most global initialization
27/// you can use [`once_cell`]'s or [`lazy_static`]'s.
28///
29/// There are two cases where init hooks are needed:
30///
31/// 1. To register handlers. In most cases, more specific registrators should be
32///    used though (e.g. [`web_handler`](macro@web_handler)).
33/// 2. For smaller latency during request processing (but see below).
34///
35/// # Influence on Request Latency
36///
37/// Note: while we will provide request processing latency metric distinct from
38/// the initialization time, this may not have the desired effect on users'
39/// experience. When request comes in and there is no preinitialized worker,
40/// it's likely that user request will need to wait for worker initialization.
41/// (We can also employ some techniques to optimize this too).
42///
43/// [`once_cell`]: https://crates.io/crates/once_cell
44/// [`lazy_static`]: https://crates.io/crates/lazy_static
45#[proc_macro_error::proc_macro_error]
46#[proc_macro_attribute]
47pub fn init_hook(_attr: TokenStream, item: TokenStream) -> TokenStream {
48    let input = syn::parse_macro_input!(item as syn::ItemFn);
49    if !input.sig.generics.params.is_empty() {
50        emit_error!(input.sig.generics, "no generics allowed on init hook");
51    }
52    if !input.sig.inputs.is_empty() {
53        emit_error!(input.sig.inputs, "no params allowed on init hook");
54    }
55    if !matches!(input.sig.output, syn::ReturnType::Default) {
56        emit_error!(input.sig.output, "no return value allowed on init hook");
57    }
58    let func_name = &input.sig.ident;
59    let hook_name = quote::format_ident!("_edgedb_sdk_init_{}", func_name);
60    quote! {
61        #input
62
63        #[export_name = stringify!(#hook_name)]
64        extern fn #hook_name() {
65            #func_name();
66        }
67
68    }.into()
69}