opengauss_bindgen_macros/
lib.rs1use proc_macro::TokenStream;
2use proc_macro2::Span;
3use quote::quote;
4use quote::ToTokens;
5use std::borrow::Borrow;
6use std::borrow::BorrowMut;
7use syn::{parse, parse_str, FnArg, ItemFn, Pat, Stmt};
8
9fn gen_opengauss_type(ty: &syn::Type) -> Box<syn::Type> {
10 match ty.to_owned().into_token_stream().to_string().as_str() {
11 "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | "bool" | "char" => {
12 Box::new(syn::Type::from(parse_str::<syn::TypePath>("i64").unwrap()))
13 }
14 "f32" | "f64" => Box::new(syn::Type::from(parse_str::<syn::TypePath>("f64").unwrap())),
15 _ => Box::new(syn::Type::from(parse_str::<syn::TypePath>("i32").unwrap())),
16 }
17}
18
19fn gen_from_expr(ty: &syn::Type, id: &str) -> String {
20 let type_str = ty.to_owned().into_token_stream().to_string();
21 match type_str.as_str() {
22 "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | "bool" | "char" => {
23 format!("{} as {}", id, type_str)
24 }
25 "f32" | "f64" => format!("{} as f64", id),
26 _ => format!("<{}>::from_opengauss_type({})", type_str, id),
27 }
28}
29
30fn gen_into_expr(return_type_str: &str, expr: syn::Expr) -> syn::Expr {
31 let expr_str = expr.into_token_stream().to_string();
32 parse_str::<syn::Expr>(&match return_type_str {
33 "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | "bool" | "char" => {
34 format!("{} as i64", expr_str)
35 }
36 "f32" | "f64" => format!("{} as f64", expr_str),
37 _ => format!("{}.into_opengauss_type()", expr_str),
38 })
39 .unwrap()
40}
41
42#[proc_macro_attribute]
55pub fn opengauss_bindgen(_attrs: TokenStream, item: TokenStream) -> TokenStream {
56 let input = match parse::<ItemFn>(item) {
57 Ok(i) => i,
58 Err(_) => {
59 return TokenStream::from(
60 syn::Error::new(
61 Span::call_site(),
62 "opengauss_bindgen operates on function definitions only",
63 )
64 .to_compile_error(),
65 )
66 }
67 };
68
69 let mut native_sig = input.sig.clone();
70 let mut generated_sig = input.sig.clone();
71 native_sig.ident = syn::Ident::new(
72 format!("__opengauss_native_{}", generated_sig.ident).as_str(),
73 Span::call_site(),
74 );
75 for raw_param in &mut generated_sig.inputs {
77 if let &mut FnArg::Typed(ref mut param) = raw_param {
78 param.ty = gen_opengauss_type(¶m.ty);
79 if let &mut Pat::Ident(ref mut id) = param.pat.borrow_mut() {
80 id.mutability = Option::None;
81 }
82 }
83 }
84 let mut return_type_str = String::new();
86 if let &syn::ReturnType::Type(_, ref ty) = &generated_sig.output {
87 return_type_str = ty.to_owned().into_token_stream().to_string();
88 generated_sig.output =
89 syn::ReturnType::Type(syn::token::RArrow::default(), gen_opengauss_type(ty));
90 }
91
92 let native_block = &input.block;
94 let mut generated_block = syn::Block {
95 brace_token: input.block.brace_token,
96 stmts: Vec::<Stmt>::new(),
97 };
98
99 let mut raw_ret_expr =
101 parse_str::<syn::Expr>(&format!("{}()", &native_sig.ident.to_string())).unwrap();
102 if let &mut syn::Expr::Call(ref mut call) = &mut raw_ret_expr {
103 for raw_param in &native_sig.inputs {
104 if let &FnArg::Typed(ref param) = raw_param {
105 if let &Pat::Ident(ref id) = param.pat.borrow() {
106 let from_expr =
107 parse_str::<syn::Expr>(&gen_from_expr(¶m.ty, &id.ident.to_string()))
108 .unwrap();
109 call.args.push(from_expr);
110 }
111 }
112 }
113 }
114 let ret_expr = gen_into_expr(&return_type_str, raw_ret_expr);
115 generated_block.stmts.push(Stmt::Expr(ret_expr));
116
117 TokenStream::from(quote! {
118 #native_sig
119 #native_block
120
121 #[no_mangle]
122 pub #generated_sig
123 #generated_block
124 })
125}