commit
0005fca934
7 changed files with 83 additions and 10 deletions
|
@ -1,6 +1,7 @@
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
use std::mem;
|
||||||
use std::os::raw::{c_char, c_void};
|
use std::os::raw::{c_char, c_void};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
@ -275,7 +276,7 @@ impl Env {
|
||||||
value: raw_value,
|
value: raw_value,
|
||||||
value_type: ValueType::Object,
|
value_type: ValueType::Object,
|
||||||
}),
|
}),
|
||||||
data,
|
mem::ManuallyDrop::new(data),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,10 +307,55 @@ impl Env {
|
||||||
value: raw_value,
|
value: raw_value,
|
||||||
value_type: ValueType::Object,
|
value_type: ValueType::Object,
|
||||||
}),
|
}),
|
||||||
data,
|
mem::ManuallyDrop::new(data),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// # Safety
|
||||||
|
/// Mostly same with `create_buffer_with_data`, but you must ensure data will be dropped **after** the `Buffer` is been GC.
|
||||||
|
///
|
||||||
|
/// And should manually trigger `Env::adjust_external_memory` after data is dropped.
|
||||||
|
pub unsafe fn create_buffer_with_manually_drop_data(&self, data: &[u8]) -> Result<JsBufferValue> {
|
||||||
|
let length = data.len();
|
||||||
|
let mut raw_value = ptr::null_mut();
|
||||||
|
let data_ptr = data.as_ptr();
|
||||||
|
check_status!(sys::napi_create_external_buffer(
|
||||||
|
self.0,
|
||||||
|
length,
|
||||||
|
data_ptr as *mut c_void,
|
||||||
|
None,
|
||||||
|
ptr::null_mut(),
|
||||||
|
&mut raw_value,
|
||||||
|
))?;
|
||||||
|
let mut changed = 0;
|
||||||
|
check_status!(sys::napi_adjust_external_memory(
|
||||||
|
self.0,
|
||||||
|
length as i64,
|
||||||
|
&mut changed
|
||||||
|
))?;
|
||||||
|
Ok(JsBufferValue::new(
|
||||||
|
JsBuffer(Value {
|
||||||
|
env: self.0,
|
||||||
|
value: raw_value,
|
||||||
|
value_type: ValueType::Object,
|
||||||
|
}),
|
||||||
|
mem::ManuallyDrop::new(Vec::from_raw_parts(data_ptr as *mut u8, length, length)),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// This function gives V8 an indication of the amount of externally allocated memory that is kept alive by JavaScript objects (i.e. a JavaScript object that points to its own memory allocated by a native module).
|
||||||
|
///
|
||||||
|
/// Registering externally allocated memory will trigger global garbage collections more often than it would otherwise.
|
||||||
|
///
|
||||||
|
/// ***ATTENTION ⚠️***, do not use this with `create_buffer_with_data/create_arraybuffer_with_data`, since these two functions already called the `adjust_external_memory` internal.
|
||||||
|
pub fn adjust_external_memory(&mut self, size: i64) -> Result<i64> {
|
||||||
|
let mut changed = 0i64;
|
||||||
|
check_status!(unsafe { sys::napi_adjust_external_memory(self.0, size, &mut changed) })?;
|
||||||
|
Ok(changed)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// This API allocates a node::Buffer object and initializes it with data copied from the passed-in buffer.
|
/// This API allocates a node::Buffer object and initializes it with data copied from the passed-in buffer.
|
||||||
/// While this is still a fully-supported data structure, in most cases using a TypedArray will suffice.
|
/// While this is still a fully-supported data structure, in most cases using a TypedArray will suffice.
|
||||||
|
@ -336,7 +382,7 @@ impl Env {
|
||||||
value: raw_value,
|
value: raw_value,
|
||||||
value_type: ValueType::Object,
|
value_type: ValueType::Object,
|
||||||
}),
|
}),
|
||||||
unsafe { Vec::from_raw_parts(copy_data as *mut u8, length, length) },
|
mem::ManuallyDrop::new(unsafe { Vec::from_raw_parts(copy_data as *mut u8, length, length) }),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,11 +55,8 @@ impl JsBufferValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(value: JsBuffer, data: Vec<u8>) -> Self {
|
pub fn new(value: JsBuffer, data: mem::ManuallyDrop<Vec<u8>>) -> Self {
|
||||||
JsBufferValue {
|
JsBufferValue { value, data }
|
||||||
value,
|
|
||||||
data: mem::ManuallyDrop::new(data),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -607,4 +607,15 @@ impl JsUnknown {
|
||||||
pub fn get_type(&self) -> Result<ValueType> {
|
pub fn get_type(&self) -> Result<ValueType> {
|
||||||
unsafe { type_of!(self.0.env, self.0.value) }
|
unsafe { type_of!(self.0.env, self.0.value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// # Safety
|
||||||
|
/// This function should be called after `JsUnknown::get_type`
|
||||||
|
/// And the `V` must be match with the return value of `get_type`
|
||||||
|
pub unsafe fn cast<V>(self) -> V
|
||||||
|
where
|
||||||
|
V: NapiValue,
|
||||||
|
{
|
||||||
|
V::from_raw_unchecked(self.0.env, self.0.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//!
|
//!
|
||||||
//! ## Feature flags
|
//! ## Feature flags
|
||||||
//!
|
//!
|
||||||
//! ### napi1 ~ napi6
|
//! ### napi1 ~ napi7
|
||||||
//!
|
//!
|
||||||
//! Because `NodeJS` N-API has versions. So there are feature flags to choose what version of `N-API` you want to build for.
|
//! Because `NodeJS` N-API has versions. So there are feature flags to choose what version of `N-API` you want to build for.
|
||||||
//! For example, if you want build a library which can be used by `node@10.17.0`, you should choose the `napi5` or lower.
|
//! For example, if you want build a library which can be used by `node@10.17.0`, you should choose the `napi5` or lower.
|
||||||
|
|
|
@ -47,3 +47,14 @@ test('strict_equals', (t) => {
|
||||||
t.false(bindings.strictEquals(NaN, NaN))
|
t.false(bindings.strictEquals(NaN, NaN))
|
||||||
t.true(bindings.strictEquals(a, a))
|
t.true(bindings.strictEquals(a, a))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('cast_unknown', (t) => {
|
||||||
|
const f = {}
|
||||||
|
const r = bindings.castUnknown(f)
|
||||||
|
t.is(f, r)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('cast_unknown will not throw', (t) => {
|
||||||
|
const f = 1
|
||||||
|
t.notThrows(() => bindings.castUnknown(f))
|
||||||
|
})
|
||||||
|
|
|
@ -26,10 +26,17 @@ pub fn strict_equals(ctx: CallContext) -> Result<JsBoolean> {
|
||||||
ctx.env.get_boolean(ctx.env.strict_equals(a, b)?)
|
ctx.env.get_boolean(ctx.env.strict_equals(a, b)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[js_function(1)]
|
||||||
|
pub fn cast_unknown(ctx: CallContext) -> Result<JsObject> {
|
||||||
|
let arg: JsUnknown = ctx.get(0)?;
|
||||||
|
Ok(unsafe { arg.cast::<JsObject>() })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn register_js(exports: &mut JsObject) -> Result<()> {
|
pub fn register_js(exports: &mut JsObject) -> Result<()> {
|
||||||
exports.create_named_method("instanceof", instanceof)?;
|
exports.create_named_method("instanceof", instanceof)?;
|
||||||
exports.create_named_method("isTypedarray", is_typedarray)?;
|
exports.create_named_method("isTypedarray", is_typedarray)?;
|
||||||
exports.create_named_method("isDataview", is_dataview)?;
|
exports.create_named_method("isDataview", is_dataview)?;
|
||||||
exports.create_named_method("strictEquals", strict_equals)?;
|
exports.create_named_method("strictEquals", strict_equals)?;
|
||||||
|
exports.create_named_method("castUnknown", cast_unknown)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
"extends": "../tsconfig.json",
|
"extends": "../tsconfig.json",
|
||||||
"include": ["."],
|
"include": ["."],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./dist"
|
"outDir": "./dist",
|
||||||
|
"rootDir": "__test__"
|
||||||
},
|
},
|
||||||
"exclude": ["dist"]
|
"exclude": ["dist"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue