sqlite_loadable_macros/
lib.rs

1use proc_macro2::Ident;
2
3use syn::{parse_macro_input, spanned::Spanned, Item};
4
5use proc_macro::TokenStream;
6use quote::quote_spanned;
7
8/// Wraps an entrypoint function to expose an unsafe extern "C" function of the same name.
9#[proc_macro_attribute]
10pub fn sqlite_entrypoint(_attr: TokenStream, item: TokenStream) -> TokenStream {
11    let ast = parse_macro_input!(item as syn::Item);
12    match ast {
13        Item::Fn(mut func) => {
14            let c_entrypoint = func.sig.ident.clone();
15
16            let original_funcname = func.sig.ident.to_string();
17            func.sig.ident = Ident::new(
18                format!("_{}", original_funcname).as_str(),
19                func.sig.ident.span(),
20            );
21
22            let prefixed_original_function = func.sig.ident.clone();
23
24            quote_spanned! {func.span()=>
25                #func
26
27                /// # Safety
28                ///
29                /// Should only be called by underlying SQLite C APIs,
30                /// like sqlite3_auto_extension and sqlite3_cancel_auto_extension.
31                #[no_mangle]
32                pub unsafe extern "C" fn #c_entrypoint(
33                    db: *mut sqlite3,
34                    pz_err_msg: *mut *mut c_char,
35                    p_api: *mut sqlite3_api_routines,
36                ) -> c_uint {
37                    register_entrypoint(db, pz_err_msg, p_api, #prefixed_original_function)
38                }
39
40
41            }
42            .into()
43        }
44        _ => panic!("Only function items are allowed on sqlite_entrypoint"),
45    }
46}
47
48/// Wraps an entrypoint function to expose an unsafe extern "C" function of the same name.
49#[proc_macro_attribute]
50pub fn sqlite_entrypoint_permanent(_attr: TokenStream, item: TokenStream) -> TokenStream {
51    let ast = parse_macro_input!(item as syn::Item);
52    match ast {
53        Item::Fn(mut func) => {
54            let c_entrypoint = func.sig.ident.clone();
55
56            let original_funcname = func.sig.ident.to_string();
57            func.sig.ident = Ident::new(
58                format!("_{}", original_funcname).as_str(),
59                func.sig.ident.span(),
60            );
61
62            let prefixed_original_function = func.sig.ident.clone();
63
64            quote_spanned! {func.span()=>
65                #func
66
67                /// # Safety
68                ///
69                /// Should only be called by underlying SQLite C APIs,
70                /// like sqlite3_auto_extension and sqlite3_cancel_auto_extension.
71                #[no_mangle]
72                pub unsafe extern "C" fn #c_entrypoint(
73                    db: *mut sqlite3,
74                    pz_err_msg: *mut *mut c_char,
75                    p_api: *mut sqlite3_api_routines,
76                ) -> c_uint {
77                    register_entrypoint_load_permanently(db, pz_err_msg, p_api, #prefixed_original_function)
78                }
79
80
81            }
82            .into()
83        }
84        _ => panic!("Only function items are allowed on sqlite_entrypoint"),
85    }
86}