deno_bindgen_macro/
lib.rs1use proc_macro::TokenStream;
4use quote::format_ident;
5use quote::quote;
6use std::env;
7use std::fs::OpenOptions;
8use std::io::Read;
9use std::io::Write;
10use std::path::Path;
11use syn::parse_macro_input;
12use syn::parse_quote;
13use syn::ItemFn;
14
15mod attrs;
16mod derive_fn;
17mod derive_struct;
18mod docs;
19mod meta;
20
21use crate::derive_fn::process_function;
22use crate::derive_struct::process_struct;
23use crate::meta::Glue;
24use crate::meta::Type;
25
26#[cfg(target_endian = "little")]
27const ENDIANNESS: bool = true;
28
29#[cfg(target_endian = "big")]
30const ENDIANNESS: bool = false;
31
32#[proc_macro_attribute]
33pub fn deno_bindgen(attr: TokenStream, input: TokenStream) -> TokenStream {
34 let metafile_path: String = match env::var("OUT_DIR") {
35 Ok(out_dir) => Path::new(&out_dir)
36 .join("bindings.json")
37 .into_os_string()
38 .into_string()
39 .unwrap(),
40 Err(_e) => String::from("bindings.json"),
41 };
42
43 let mut metadata: Glue =
44 match OpenOptions::new().read(true).open(metafile_path.as_str()) {
45 Ok(mut fd) => {
46 let mut meta = String::new();
47 fd.read_to_string(&mut meta)
48 .expect("Error reading meta file");
49
50 serde_json::from_str(&meta).unwrap_or_default()
51 }
52 Err(_) => Glue {
53 little_endian: ENDIANNESS,
54 name: env::var("CARGO_CRATE_NAME").unwrap_or_default(),
55 ..Default::default()
56 },
57 };
58
59 let mut metafile = OpenOptions::new()
60 .write(true)
61 .create(true)
62 .open(metafile_path.as_str())
63 .expect("Error opening meta file");
64
65 match syn::parse::<ItemFn>(input.clone()) {
66 Ok(func) => {
67 let attr = parse_macro_input!(attr as syn::AttributeArgs);
68 let symbol = process_function(func.clone(), attr, &mut metadata).unwrap();
69
70 let mut params = vec![];
71 let mut overrides = vec![];
72 let mut input_idents = vec![];
73 let mut c_index = 0;
74
75 for parameter in symbol.parameters {
76 match parameter {
77 Type::StructEnum { .. } => {
78 let ident = format_ident!("arg{}", c_index.to_string());
79 params.push(quote! { #ident: *const u8 });
80
81 c_index += 1;
82 let len_ident = format_ident!("arg{}", c_index.to_string());
83 params.push(quote! { #len_ident: usize });
84
85 overrides.push(quote! {
86 let buf = unsafe {
87 ::std::slice::from_raw_parts(#ident, #len_ident)
88 };
89 let #ident = deno_bindgen::serde_json::from_slice(buf).unwrap();
90 });
91
92 input_idents.push(ident);
93 }
94 Type::Str | Type::Buffer | Type::BufferMut => {
95 let ident = format_ident!("arg{}", c_index.to_string());
96 match parameter {
97 Type::Str | Type::Buffer => {
98 params.push(quote! { #ident: *const u8 })
99 }
100 Type::BufferMut => params.push(quote! { #ident: *mut u8 }),
101 _ => unreachable!(),
102 };
103
104 c_index += 1;
105 let len_ident = format_ident!("arg{}", c_index.to_string());
106 params.push(quote! { #len_ident: usize });
107
108 let return_type = match parameter {
109 Type::Str => quote! { ::std::str::from_utf8(buf).unwrap() },
110 Type::Buffer | Type::BufferMut => quote! { buf },
111 _ => unreachable!(),
112 };
113
114 let buf_expr = match parameter {
115 Type::Str | Type::Buffer => {
116 quote! { let buf = ::std::slice::from_raw_parts(#ident, #len_ident); }
117 }
118 Type::BufferMut => {
119 quote! { let mut buf: &'sym mut [u8] = ::std::slice::from_raw_parts_mut(#ident, #len_ident);
122 }
123 }
124 _ => unreachable!(),
125 };
126
127 overrides.push(quote! {
128 let #ident = unsafe {
129 #buf_expr
130 #return_type
131 };
132 });
133
134 input_idents.push(ident);
135 }
136 _ => {
138 let ident = format_ident!("arg{}", c_index.to_string());
139 let ty = syn::Type::from(parameter);
140 params.push(quote! { #ident: #ty });
141 input_idents.push(ident);
142 }
143 };
144
145 c_index += 1;
146 }
147
148 let (result, transformer) = match symbol.result {
149 Type::Buffer
150 | Type::Str => {
153 let ty = parse_quote! { *const u8 };
154 let slice = match symbol.result {
155 Type::Str => quote! {
156 result.as_bytes()
157 },
158 _ => quote! { result }
159 };
160 let transformer = quote! {
161 let length = (result.len() as u32).to_be_bytes();
162 let mut v = length.to_vec();
163 v.extend_from_slice(&#slice);
164
165 ::std::mem::forget(result);
166 let result = v.as_ptr();
167 ::std::mem::forget(v);
169 result
170 };
171
172 (ty, transformer)
173 }
174 Type::StructEnum { .. } => {
175 let ty = parse_quote! { *const u8 };
176 let transformer = quote! {
177 let json = deno_bindgen::serde_json::to_string(&result).expect("Failed to serialize as JSON");
178 let encoded = json.into_bytes();
179 let length = (encoded.len() as u32).to_be_bytes();
180 let mut v = length.to_vec();
181 v.extend(encoded.clone());
182
183 let ret = v.as_ptr();
184 ::std::mem::forget(v);
186 ret
187 };
188
189 (ty, transformer)
190 }
191 Type::Ptr => (parse_quote! { *const u8 }, quote! { result }),
192 _ => (syn::Type::from(symbol.result), quote! { result }),
193 };
194
195 let name = &func.sig.ident;
196 let fn_inputs = &func.sig.inputs;
197 let fn_output = &func.sig.output;
198 let fn_generics = &func.sig.generics;
199 let fn_block = &func.block;
200
201 let overrides = overrides
202 .iter()
203 .fold(quote! {}, |acc, new| quote! { #acc #new });
204
205 metafile
206 .write_all(&serde_json::to_vec(&metadata).unwrap())
207 .unwrap();
208
209 TokenStream::from(quote! {
210 #[no_mangle]
211 pub extern "C" fn #name <'sym> (#(#params,) *) -> #result {
212 fn __inner_impl #fn_generics (#fn_inputs) #fn_output #fn_block
213 #overrides
214 let result = __inner_impl(#(#input_idents, ) *);
215 #transformer
216 }
217 })
218 }
219 Err(_) => {
220 let input = syn::parse_macro_input!(input as syn::DeriveInput);
221 process_struct(&mut metadata, input.clone()).unwrap();
222
223 metafile
224 .write_all(&serde_json::to_vec(&metadata).unwrap())
225 .unwrap();
226
227 TokenStream::from(quote! {
228 #[derive(::serde::Deserialize,::serde::Serialize)]
229 #input
230 })
231 }
232 }
233}