esbuild_rs/api/
transform.rs1use std::future::Future;
2use std::os::raw::c_void;
3use std::pin::Pin;
4use std::sync::{Arc, Mutex};
5use std::task::{Context, Poll, Waker};
6
7use libc::size_t;
8
9use crate::bridge::{GoString, GoTransform};
10use crate::wrapper::{Message, SliceContainer, StrContainer, TransformOptions, TransformResult};
11
12struct TransformInvocationData {
13 src_vec_arc_raw: Option<*const Vec<u8>>,
14 opt_arc_raw: Option<*const TransformOptions>,
15 cb_trait_ptr: *mut c_void,
16}
17
18extern "C" fn transform_callback(
19 raw_cb_data: *mut c_void,
20 code: StrContainer,
21 map: StrContainer,
22 raw_errors: *mut Message,
23 errors_len: size_t,
24 raw_warnings: *mut Message,
25 warnings_len: size_t,
26) -> () {
27 unsafe {
28 let cb_data: Box<TransformInvocationData> = Box::from_raw(raw_cb_data as *mut _);
29
30 if let Some(ptr) = cb_data.src_vec_arc_raw {
32 let _: Arc<Vec<u8>> = Arc::from_raw(ptr);
33 };
34
35 if let Some(ptr) = cb_data.opt_arc_raw {
37 let _: Arc<TransformOptions> = Arc::from_raw(ptr);
38 };
39
40 let rust_cb_trait_box: Box<Box<dyn FnOnce(TransformResult)>> =
41 Box::from_raw(cb_data.cb_trait_ptr as *mut _);
42
43 let errors = SliceContainer {
44 ptr: raw_errors,
45 len: errors_len,
46 };
47 let warnings = SliceContainer {
48 ptr: raw_warnings,
49 len: warnings_len,
50 };
51
52 rust_cb_trait_box(TransformResult {
53 code,
54 map,
55 errors,
56 warnings,
57 });
58 };
59}
60
61unsafe fn call_ffi_transform(
62 cb_data: *mut TransformInvocationData,
63 go_code: GoString,
64 options: &TransformOptions,
65) -> () {
66 #[cfg(target_env = "msvc")]
67 #[allow(non_snake_case)]
68 let GoTransform =
69 std::mem::transmute::<_, GoTransform>(crate::bridge::DLL.get_function("GoTransform"));
70
71 GoTransform(
73 libc::malloc,
74 transform_callback,
75 cb_data as *mut c_void,
76 go_code,
77 options.ffiapi_ptr,
78 );
79}
80
81pub unsafe fn transform_direct_unmanaged<F>(code: &[u8], options: &TransformOptions, cb: F) -> ()
82where
83 F: FnOnce(TransformResult),
84{
85 let go_code = GoString::from_bytes_unmanaged(code);
87
88 let cb_box = Box::new(cb) as Box<dyn FnOnce(TransformResult)>;
90 let cb_trait_box = Box::new(cb_box);
91 let cb_trait_ptr = Box::into_raw(cb_trait_box);
92
93 let data = Box::into_raw(Box::new(TransformInvocationData {
94 src_vec_arc_raw: None,
95 opt_arc_raw: None,
96 cb_trait_ptr: cb_trait_ptr as *mut c_void,
97 }));
98
99 call_ffi_transform(data, go_code, options);
100}
101
102pub fn transform_direct<F>(code: Arc<Vec<u8>>, options: Arc<TransformOptions>, cb: F) -> ()
146where
147 F: FnOnce(TransformResult),
148 F: Send + 'static,
149{
150 let go_code = unsafe { GoString::from_bytes_unmanaged(&code) };
152
153 let cb_box = Box::new(cb) as Box<dyn FnOnce(TransformResult)>;
155 let cb_trait_box = Box::new(cb_box);
156 let cb_trait_ptr = Box::into_raw(cb_trait_box);
157
158 let data = Box::into_raw(Box::new(TransformInvocationData {
159 src_vec_arc_raw: Some(Arc::into_raw(code.clone())),
160 opt_arc_raw: Some(Arc::into_raw(options.clone())),
161 cb_trait_ptr: cb_trait_ptr as *mut c_void,
162 }));
163
164 unsafe {
165 call_ffi_transform(data, go_code, options.as_ref());
166 };
167}
168
169struct TransformFutureState {
170 result: Option<TransformResult>,
171 waker: Option<Waker>,
172}
173
174pub struct TransformFuture {
175 state: Arc<Mutex<TransformFutureState>>,
176}
177
178pub fn transform(code: Arc<Vec<u8>>, options: Arc<TransformOptions>) -> TransformFuture {
208 let state = Arc::new(Mutex::new(TransformFutureState {
209 result: None,
210 waker: None,
211 }));
212 let state_cb_copy = state.clone();
213 transform_direct(code, options, move |result| {
214 let mut state = state_cb_copy.lock().unwrap();
215 state.result = Some(result);
216 if let Some(waker) = state.waker.take() {
217 waker.wake();
218 };
219 });
220 TransformFuture { state }
221}
222
223impl Future for TransformFuture {
224 type Output = TransformResult;
225
226 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
227 let mut state = self.state.lock().unwrap();
228 match state.result.take() {
229 Some(result) => Poll::Ready(result),
230 None => {
231 state.waker = Some(cx.waker().clone());
232 Poll::Pending
233 }
234 }
235 }
236}