1use proc_macro::TokenStream;
6use quote::quote;
7use syn::{ItemFn, parse_macro_input};
8
9#[proc_macro]
18pub fn plugin(_input: TokenStream) -> TokenStream {
19 let expanded = quote! {
20 #[unsafe(no_mangle)]
21 pub unsafe extern "C" fn pgdog_rustc_version(output: *mut pgdog_plugin::PdStr) {
22 let version = pgdog_plugin::comp::rustc_version();
23 unsafe {
24 *output = version;
25 }
26 }
27
28 #[unsafe(no_mangle)]
29 pub unsafe extern "C" fn pgdog_pg_query_version(output: *mut pgdog_plugin::PdStr) {
30 let version: pgdog_plugin::PdStr = option_env!("PGDOG_PGQUERY_VERSION")
31 .unwrap_or_default()
32 .into();
33 unsafe {
34 *output = version;
35 }
36 }
37
38 #[unsafe(no_mangle)]
39 pub unsafe extern "C" fn pgdog_plugin_version(output: *mut pgdog_plugin::PdStr) {
40 let version: pgdog_plugin::PdStr = env!("CARGO_PKG_VERSION").into();
41 unsafe {
42 *output = version;
43 }
44 }
45 };
46 TokenStream::from(expanded)
47}
48
49#[proc_macro_attribute]
51pub fn init(_attr: TokenStream, item: TokenStream) -> TokenStream {
52 let input_fn = parse_macro_input!(item as ItemFn);
53 let fn_name = &input_fn.sig.ident;
54
55 let expanded = quote! {
56
57 #[unsafe(no_mangle)]
58 pub extern "C" fn pgdog_init() {
59 #input_fn
60
61 #fn_name();
62 }
63 };
64
65 TokenStream::from(expanded)
66}
67
68#[proc_macro_attribute]
70pub fn fini(_attr: TokenStream, item: TokenStream) -> TokenStream {
71 let input_fn = parse_macro_input!(item as ItemFn);
72 let fn_name = &input_fn.sig.ident;
73
74 let expanded = quote! {
75 #[unsafe(no_mangle)]
76 pub extern "C" fn pgdog_fini() {
77 #input_fn
78
79 #fn_name();
80 }
81 };
82
83 TokenStream::from(expanded)
84}
85
86#[proc_macro_attribute]
88pub fn route(_attr: TokenStream, item: TokenStream) -> TokenStream {
89 let input_fn = parse_macro_input!(item as ItemFn);
90 let fn_name = &input_fn.sig.ident;
91 let fn_inputs = &input_fn.sig.inputs;
92
93 let (first_param_name, _) = fn_inputs
95 .iter()
96 .filter_map(|input| {
97 if let syn::FnArg::Typed(pat_type) = input {
98 if let syn::Pat::Ident(pat_ident) = &*pat_type.pat {
99 Some((pat_ident.ident.clone(), pat_type.ty.clone()))
100 } else {
101 None
102 }
103 } else {
104 None
105 }
106 })
107 .next()
108 .expect("Route function must have at least one named parameter");
109
110 let expanded = quote! {
111 #[unsafe(no_mangle)]
112 pub unsafe extern "C" fn pgdog_route(#first_param_name: pgdog_plugin::PdRouterContext, output: *mut pgdog_plugin::PdRoute) {
113 #input_fn
114
115 let pgdog_context: pgdog_plugin::Context = #first_param_name.into();
116 let route: pgdog_plugin::PdRoute = #fn_name(pgdog_context).into();
117 unsafe {
118 *output = route;
119 }
120 }
121 };
122
123 TokenStream::from(expanded)
124}