fix(napi): arraybuffer implement
close https://github.com/napi-rs/napi-rs/issues/68
This commit is contained in:
parent
c1b957a268
commit
3eecf1fc5f
6 changed files with 120 additions and 180 deletions
|
@ -264,22 +264,22 @@ impl Env {
|
|||
))
|
||||
}
|
||||
|
||||
pub fn create_arraybuffer(&self, length: u64) -> Result<JsArrayBuffer> {
|
||||
pub fn create_arraybuffer(&self, length: u64) -> Result<JsArrayBufferValue> {
|
||||
let mut raw_value = ptr::null_mut();
|
||||
let mut data = Vec::with_capacity(length as usize);
|
||||
let mut data_ptr = data.as_mut_ptr();
|
||||
let mut data: Vec<u8> = Vec::with_capacity(length as usize);
|
||||
let mut data_ptr = data.as_mut_ptr() as *mut c_void;
|
||||
check_status(unsafe {
|
||||
sys::napi_create_arraybuffer(self.0, length, &mut data_ptr, &mut raw_value)
|
||||
})?;
|
||||
mem::forget(data);
|
||||
let mut array_buffer = JsArrayBuffer::from_raw_unchecked(self.0, raw_value);
|
||||
array_buffer.data = data_ptr as *const u8;
|
||||
array_buffer.len = length;
|
||||
Ok(array_buffer)
|
||||
|
||||
Ok(JsArrayBufferValue::new(
|
||||
JsArrayBuffer::from_raw_unchecked(self.0, raw_value),
|
||||
data,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn create_arraybuffer_with_data(&self, data: Vec<u8>) -> Result<JsArrayBuffer> {
|
||||
let length = data.len() as u64;
|
||||
pub fn create_arraybuffer_with_data(&self, data: Vec<u8>) -> Result<JsArrayBufferValue> {
|
||||
let mut length = data.len() as u64;
|
||||
let mut raw_value = ptr::null_mut();
|
||||
let data_ptr = data.as_ptr();
|
||||
check_status(unsafe {
|
||||
|
@ -288,17 +288,21 @@ impl Env {
|
|||
data_ptr as *mut c_void,
|
||||
length,
|
||||
Some(drop_buffer),
|
||||
&length as *const _ as *mut c_void,
|
||||
&mut length as *mut u64 as *mut c_void,
|
||||
&mut raw_value,
|
||||
)
|
||||
})?;
|
||||
let mut changed = 0;
|
||||
check_status(unsafe { sys::napi_adjust_external_memory(self.0, length as i64, &mut changed) })?;
|
||||
mem::forget(data);
|
||||
let mut array_buffer = JsArrayBuffer::from_raw_unchecked(self.0, raw_value);
|
||||
array_buffer.data = data_ptr as *const u8;
|
||||
array_buffer.len = length;
|
||||
Ok(array_buffer)
|
||||
|
||||
Ok(JsArrayBufferValue::new(
|
||||
JsArrayBuffer(Value {
|
||||
env: self.0,
|
||||
value: raw_value,
|
||||
value_type: ValueType::Object,
|
||||
}),
|
||||
data,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn create_function(&self, name: &str, callback: Callback) -> Result<JsFunction> {
|
||||
|
|
|
@ -1,182 +1,69 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
|
||||
use super::{JsNumber, JsObject, JsString, JsUnknown, NapiValue, Status, Value, ValueType};
|
||||
use super::Value;
|
||||
use crate::error::check_status;
|
||||
use crate::{sys, Error, Result};
|
||||
use crate::{sys, JsUnknown, Ref, Result};
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct JsArrayBuffer(pub(crate) Value);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JsArrayBuffer {
|
||||
pub value: JsObject,
|
||||
pub data: *const u8,
|
||||
pub len: u64,
|
||||
pub struct JsArrayBufferValue {
|
||||
pub(crate) value: JsArrayBuffer,
|
||||
data: mem::ManuallyDrop<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl JsArrayBuffer {
|
||||
pub(crate) fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> Self {
|
||||
Self {
|
||||
value: JsObject(Value {
|
||||
env,
|
||||
value,
|
||||
value_type: ValueType::Object,
|
||||
}),
|
||||
data: ptr::null(),
|
||||
len: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_unknown(self) -> Result<JsUnknown> {
|
||||
JsUnknown::from_raw(self.value.0.env, self.value.0.value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn coerce_to_number(self) -> Result<JsNumber> {
|
||||
let mut new_raw_value = ptr::null_mut();
|
||||
check_status(unsafe {
|
||||
sys::napi_coerce_to_number(self.value.0.env, self.value.0.value, &mut new_raw_value)
|
||||
})?;
|
||||
Ok(JsNumber(Value {
|
||||
env: self.value.0.env,
|
||||
value: new_raw_value,
|
||||
value_type: ValueType::Number,
|
||||
}))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn coerce_to_string(self) -> Result<JsString> {
|
||||
let mut new_raw_value = ptr::null_mut();
|
||||
check_status(unsafe {
|
||||
sys::napi_coerce_to_string(self.value.0.env, self.value.0.value, &mut new_raw_value)
|
||||
})?;
|
||||
Ok(JsString(Value {
|
||||
env: self.value.0.env,
|
||||
value: new_raw_value,
|
||||
value_type: ValueType::String,
|
||||
}))
|
||||
}
|
||||
#[inline]
|
||||
pub fn coerce_to_object(self) -> Result<JsObject> {
|
||||
let mut new_raw_value = ptr::null_mut();
|
||||
check_status(unsafe {
|
||||
sys::napi_coerce_to_object(self.value.0.env, self.value.0.value, &mut new_raw_value)
|
||||
})?;
|
||||
Ok(JsObject(Value {
|
||||
env: self.value.0.env,
|
||||
value: new_raw_value,
|
||||
value_type: ValueType::Object,
|
||||
}))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(napi5)]
|
||||
pub fn is_date(&self) -> Result<bool> {
|
||||
let mut is_date = true;
|
||||
check_status(unsafe { sys::napi_is_date(self.value.0.env, self.value.0.value, &mut is_date) })?;
|
||||
Ok(is_date)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_error(&self) -> Result<bool> {
|
||||
let mut result = false;
|
||||
check_status(unsafe { sys::napi_is_error(self.value.0.env, self.value.0.value, &mut result) })?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_typedarray(&self) -> Result<bool> {
|
||||
let mut result = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_is_typedarray(self.value.0.env, self.value.0.value, &mut result)
|
||||
})?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_dataview(&self) -> Result<bool> {
|
||||
let mut result = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_is_dataview(self.value.0.env, self.value.0.value, &mut result)
|
||||
})?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_array(&self) -> Result<bool> {
|
||||
let mut is_array = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_is_array(self.value.0.env, self.value.0.value, &mut is_array)
|
||||
})?;
|
||||
Ok(is_array)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_buffer(&self) -> Result<bool> {
|
||||
let mut is_buffer = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_is_buffer(self.value.0.env, self.value.0.value, &mut is_buffer)
|
||||
})?;
|
||||
Ok(is_buffer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn instanceof<Constructor: NapiValue>(&self, constructor: Constructor) -> Result<bool> {
|
||||
let mut result = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_instanceof(
|
||||
self.value.0.env,
|
||||
self.value.0.value,
|
||||
constructor.raw(),
|
||||
&mut result,
|
||||
)
|
||||
})?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl NapiValue for JsArrayBuffer {
|
||||
fn raw(&self) -> sys::napi_value {
|
||||
self.value.0.value
|
||||
}
|
||||
|
||||
fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
|
||||
pub fn into_value(self) -> Result<JsArrayBufferValue> {
|
||||
let mut data = ptr::null_mut();
|
||||
let mut len: u64 = 0;
|
||||
check_status(unsafe { sys::napi_get_arraybuffer_info(env, value, &mut data, &mut len) })?;
|
||||
Ok(JsArrayBuffer {
|
||||
value: JsObject(Value {
|
||||
env,
|
||||
value,
|
||||
value_type: ValueType::Object,
|
||||
check_status(unsafe {
|
||||
sys::napi_get_arraybuffer_info(self.0.env, self.0.value, &mut data, &mut len)
|
||||
})?;
|
||||
Ok(JsArrayBufferValue {
|
||||
data: mem::ManuallyDrop::new(unsafe {
|
||||
Vec::from_raw_parts(data as *mut _, len as usize, len as usize)
|
||||
}),
|
||||
data: data as *const u8,
|
||||
len,
|
||||
value: self,
|
||||
})
|
||||
}
|
||||
|
||||
fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> Self {
|
||||
let mut data = ptr::null_mut();
|
||||
let mut len: u64 = 0;
|
||||
let status = unsafe { sys::napi_get_arraybuffer_info(env, value, &mut data, &mut len) };
|
||||
debug_assert!(
|
||||
Status::from(status) == Status::Ok,
|
||||
"napi_get_arraybuffer_info failed"
|
||||
);
|
||||
JsArrayBuffer {
|
||||
value: JsObject(Value {
|
||||
env,
|
||||
value,
|
||||
value_type: ValueType::Object,
|
||||
}),
|
||||
data: data as *const u8,
|
||||
len,
|
||||
}
|
||||
#[inline]
|
||||
pub fn into_ref(self) -> Result<Ref<JsArrayBufferValue>> {
|
||||
Ref::new(self.0, 1, self.into_value()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<JsUnknown> for JsArrayBuffer {
|
||||
type Error = Error;
|
||||
fn try_from(value: JsUnknown) -> Result<JsArrayBuffer> {
|
||||
JsArrayBuffer::from_raw(value.0.env, value.0.value)
|
||||
impl JsArrayBufferValue {
|
||||
pub fn new(value: JsArrayBuffer, data: Vec<u8>) -> Self {
|
||||
JsArrayBufferValue {
|
||||
value,
|
||||
data: mem::ManuallyDrop::new(data),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_raw(self) -> JsArrayBuffer {
|
||||
self.value
|
||||
}
|
||||
|
||||
pub fn into_unknown(self) -> Result<JsUnknown> {
|
||||
self.value.into_unknown()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for JsArrayBufferValue {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.data.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for JsArrayBufferValue {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
self.data.as_slice()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ mod value;
|
|||
mod value_ref;
|
||||
mod value_type;
|
||||
|
||||
pub use arraybuffer::JsArrayBuffer;
|
||||
pub use arraybuffer::*;
|
||||
#[cfg(napi6)]
|
||||
pub use bigint::JsBigint;
|
||||
pub use boolean::JsBoolean;
|
||||
|
@ -231,6 +231,7 @@ impl_js_value_methods!(JsUnknown);
|
|||
impl_js_value_methods!(JsUndefined);
|
||||
impl_js_value_methods!(JsNull);
|
||||
impl_js_value_methods!(JsBoolean);
|
||||
impl_js_value_methods!(JsArrayBuffer);
|
||||
impl_js_value_methods!(JsBuffer);
|
||||
impl_js_value_methods!(JsNumber);
|
||||
impl_js_value_methods!(JsString);
|
||||
|
@ -245,6 +246,7 @@ impl_napi_value_trait!(JsUndefined, Undefined);
|
|||
impl_napi_value_trait!(JsNull, Null);
|
||||
impl_napi_value_trait!(JsBoolean, Boolean);
|
||||
impl_napi_value_trait!(JsBuffer, Object);
|
||||
impl_napi_value_trait!(JsArrayBuffer, Object);
|
||||
impl_napi_value_trait!(JsNumber, Number);
|
||||
impl_napi_value_trait!(JsString, String);
|
||||
impl_napi_value_trait!(JsObject, Object);
|
||||
|
|
8
test_module/__test__/arraybuffer.spec.ts
Normal file
8
test_module/__test__/arraybuffer.spec.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import test from 'ava'
|
||||
|
||||
const bindings = require('../index.node')
|
||||
|
||||
test('should get arraybuffer length', (t) => {
|
||||
const fixture = Buffer.from('wow, hello')
|
||||
t.is(bindings.getArraybufferLength(fixture.buffer), fixture.buffer.byteLength)
|
||||
})
|
37
test_module/src/arraybuffer.rs
Normal file
37
test_module/src/arraybuffer.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
use std::ffi::CStr;
|
||||
use std::str;
|
||||
|
||||
use napi::{CallContext, JsArrayBuffer, JsNumber, JsString, Module, Result};
|
||||
|
||||
#[js_function(1)]
|
||||
pub fn get_arraybuffer_length(ctx: CallContext) -> Result<JsNumber> {
|
||||
let buffer = ctx.get::<JsArrayBuffer>(0)?.into_value()?;
|
||||
ctx.env.create_uint32((&buffer).len() as u32)
|
||||
}
|
||||
|
||||
#[js_function(1)]
|
||||
pub fn arraybuffer_to_string(ctx: CallContext) -> Result<JsString> {
|
||||
let buffer = ctx.get::<JsArrayBuffer>(0)?.into_value()?;
|
||||
ctx
|
||||
.env
|
||||
.create_string(str_from_null_terminated_utf8_safe(&buffer))
|
||||
}
|
||||
|
||||
fn str_from_null_terminated_utf8_safe(s: &[u8]) -> &str {
|
||||
if s.iter().any(|&x| x == 0) {
|
||||
unsafe { str_from_null_terminated_utf8(s) }
|
||||
} else {
|
||||
str::from_utf8(s).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
// unsafe: s must contain a null byte
|
||||
unsafe fn str_from_null_terminated_utf8(s: &[u8]) -> &str {
|
||||
CStr::from_ptr(s.as_ptr() as *const _).to_str().unwrap()
|
||||
}
|
||||
|
||||
pub fn register_js(module: &mut Module) -> Result<()> {
|
||||
module.create_named_method("getArraybufferLength", get_arraybuffer_length)?;
|
||||
module.create_named_method("arraybufferToString", arraybuffer_to_string)?;
|
||||
Ok(())
|
||||
}
|
|
@ -18,6 +18,7 @@ mod napi6;
|
|||
#[cfg(napi4)]
|
||||
mod tokio_rt;
|
||||
|
||||
mod arraybuffer;
|
||||
mod buffer;
|
||||
mod class;
|
||||
mod either;
|
||||
|
@ -43,6 +44,7 @@ fn init(module: &mut Module) -> Result<()> {
|
|||
serde::register_js(module)?;
|
||||
task::register_js(module)?;
|
||||
external::register_js(module)?;
|
||||
arraybuffer::register_js(module)?;
|
||||
buffer::register_js(module)?;
|
||||
either::register_js(module)?;
|
||||
symbol::register_js(module)?;
|
||||
|
|
Loading…
Reference in a new issue