diff --git a/nodejs/binding.c b/nodejs/binding.c index ec5ed28..5151940 100644 --- a/nodejs/binding.c +++ b/nodejs/binding.c @@ -40,22 +40,13 @@ static inline bool napi_is(napi_env env, napi_value value, napi_is_pred pred) { return res; } -typedef struct js_min_buf_metadata { - napi_ref src_buf_ref; -} js_min_buf_metadata; - void js_cfg_finalizer(napi_env env, void* finalize_data, void* _finalize_hint) { ffi_drop_cfg((Cfg const*) finalize_data); } -void js_min_buf_finalizer(napi_env env, void* _finalize_data, void* finalize_hint) { - js_min_buf_metadata* metadata = (js_min_buf_metadata*) finalize_hint; - assert_ok(napi_delete_reference(env, metadata->src_buf_ref)); - free(metadata); -} - -void js_copy_min_buf_finalizer(napi_env env, void* _finalize_data, void* finalize_hint) { - free(finalize_hint); +void js_output_buf_finalizer(napi_env env, void* _finalize_data, void* finalize_hint) { + ffi_output* metadata = (ffi_output*) finalize_hint; + ffi_drop_output(metadata); } napi_value node_method_create_configuration(napi_env env, napi_callback_info info) { @@ -160,12 +151,11 @@ napi_value node_method_minify(napi_env env, napi_callback_info info) { } Cfg const* cfg = (Cfg const*) cfg_raw; - // Run minifier in place. - size_t min_len; - ffi_in_place(src_data_copy, src_data_len, cfg, &min_len); + // Run minifier. + ffi_output const* output = ffi_minify(src_data_copy, src_data_len, cfg); // Create minified buffer with copied memory. - if (napi_create_external_buffer(env, min_len, src_data_copy, js_copy_min_buf_finalizer, src_data_copy, &min_buf_rv) != napi_ok) { + if (napi_create_external_buffer(env, output->len, output->data, js_output_buf_finalizer, (void*) output, &min_buf_rv) != napi_ok) { assert_ok(napi_throw_error(env, NULL, "Failed to create minified buffer")); goto rollback; } diff --git a/nodejs/native/src/lib.rs b/nodejs/native/src/lib.rs index 70ff066..7c49da4 100644 --- a/nodejs/native/src/lib.rs +++ b/nodejs/native/src/lib.rs @@ -1,5 +1,5 @@ use minify_html::{minify, Cfg}; -use std::slice; +use std::{mem, slice}; #[no_mangle] pub extern "C" fn ffi_create_cfg( @@ -31,19 +31,35 @@ pub extern "C" fn ffi_drop_cfg(cfg: *const Cfg) -> () { }; } +#[repr(C)] +pub struct ffi_output { + data: *mut u8, + len: usize, + cap: usize, +} + +#[no_mangle] +pub extern "C" fn ffi_drop_output(ptr: *const ffi_output) -> () { + unsafe { + let out = Box::from_raw(ptr as *mut ffi_output); + Vec::from_raw_parts(out.data, out.len, out.cap); + }; +} + #[no_mangle] // TODO Return result memory (let Node.js manage GC) instead of overwriting source. -pub extern "C" fn ffi_in_place( - code: *mut u8, +pub extern "C" fn ffi_minify( + code: *const u8, code_len: usize, cfg: *const Cfg, - out_min_len: *mut usize, -) { - let code_slice = unsafe { slice::from_raw_parts_mut(code, code_len) }; - let min_code = minify(code_slice, unsafe { &*cfg }); - let min_len = min_code.len(); - code_slice[..min_len].copy_from_slice(&min_code); - unsafe { - *out_min_len = min_len; - } +) -> *const ffi_output { + let code_slice = unsafe { slice::from_raw_parts(code, code_len) }; + let mut out_code = minify(code_slice, unsafe { &*cfg }); + let res = Box::into_raw(Box::new(ffi_output { + data: out_code.as_mut_ptr(), + len: out_code.len(), + cap: out_code.capacity(), + })); + mem::forget(out_code); + res }