Avoid Node.js double copying of result

This commit is contained in:
Wilson Lin 2021-08-08 00:33:17 +10:00
parent 397327bdeb
commit d20d6c6a18
2 changed files with 34 additions and 28 deletions

View File

@ -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;
}

View File

@ -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
}