Merge pull request #578 from napi-rs/arraybuffer

feat(napi): impl more types AsRef and AsMut for TypedArray
This commit is contained in:
LongYinan 2021-05-25 10:56:03 +08:00 committed by GitHub
commit b707d9bb82
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 157 additions and 39 deletions

View file

@ -417,7 +417,8 @@ impl Env {
Ok(JsArrayBufferValue::new(
unsafe { JsArrayBuffer::from_raw_unchecked(self.0, raw_value) },
mem::ManuallyDrop::new(data),
data_ptr as *mut c_void,
length,
))
}
@ -437,13 +438,15 @@ impl Env {
)
})?;
mem::forget(data);
Ok(JsArrayBufferValue::new(
JsArrayBuffer(Value {
env: self.0,
value: raw_value,
value_type: ValueType::Object,
}),
mem::ManuallyDrop::new(data),
data_ptr as *mut c_void,
length,
))
}
@ -486,7 +489,8 @@ impl Env {
value: raw_value,
value_type: ValueType::Object,
}),
mem::ManuallyDrop::new(Vec::from_raw_parts(data as *mut u8, length, length)),
data as *mut c_void,
length,
))
}

View file

@ -1,4 +1,3 @@
use std::mem;
use std::ops::{Deref, DerefMut};
use std::os::raw::c_void;
use std::ptr;
@ -10,7 +9,8 @@ pub struct JsArrayBuffer(pub(crate) Value);
pub struct JsArrayBufferValue {
pub(crate) value: JsArrayBuffer,
data: mem::ManuallyDrop<Vec<u8>>,
len: usize,
data: *mut c_void,
}
pub struct JsTypedArray(pub(crate) Value);
@ -34,6 +34,7 @@ pub struct JsDataViewValue {
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum TypedArrayType {
Int8 = 0,
Uint8,
@ -44,7 +45,9 @@ pub enum TypedArrayType {
Uint32,
Float32,
Float64,
#[cfg(feature = "napi6")]
BigInt64,
#[cfg(feature = "napi6")]
BigUint64,
/// compatible with higher versions
@ -63,7 +66,9 @@ impl From<sys::napi_typedarray_type> for TypedArrayType {
sys::TypedarrayType::napi_uint32_array => Self::Uint32,
sys::TypedarrayType::napi_float32_array => Self::Float32,
sys::TypedarrayType::napi_float64_array => Self::Float64,
#[cfg(feature = "napi6")]
sys::TypedarrayType::napi_bigint64_array => Self::BigInt64,
#[cfg(feature = "napi6")]
sys::TypedarrayType::napi_biguint64_array => Self::BigUint64,
_ => Self::Unknown,
}
@ -72,7 +77,7 @@ impl From<sys::napi_typedarray_type> for TypedArrayType {
impl From<TypedArrayType> for sys::napi_typedarray_type {
fn from(value: TypedArrayType) -> sys::napi_typedarray_type {
value as _
value as i32
}
}
@ -98,16 +103,12 @@ impl JsArrayBuffer {
let mut data = ptr::null_mut();
let mut len: usize = 0;
check_status!(unsafe {
sys::napi_get_arraybuffer_info(
self.0.env,
self.0.value,
&mut data,
&mut len as *mut usize as *mut _,
)
sys::napi_get_arraybuffer_info(self.0.env, self.0.value, &mut data, &mut len as *mut usize)
})?;
Ok(JsArrayBufferValue {
data: mem::ManuallyDrop::new(unsafe { Vec::from_raw_parts(data as *mut _, len, len) }),
data,
value: self,
len,
})
}
@ -163,8 +164,8 @@ impl JsArrayBuffer {
impl JsArrayBufferValue {
#[inline]
pub fn new(value: JsArrayBuffer, data: mem::ManuallyDrop<Vec<u8>>) -> Self {
JsArrayBufferValue { value, data }
pub fn new(value: JsArrayBuffer, data: *mut c_void, len: usize) -> Self {
JsArrayBufferValue { value, len, data }
}
#[inline]
@ -180,7 +181,13 @@ impl JsArrayBufferValue {
impl AsRef<[u8]> for JsArrayBufferValue {
fn as_ref(&self) -> &[u8] {
self.data.as_slice()
unsafe { slice::from_raw_parts(self.data as *const u8, self.len) }
}
}
impl AsMut<[u8]> for JsArrayBufferValue {
fn as_mut(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.data as *mut u8, self.len) }
}
}
@ -188,13 +195,13 @@ impl Deref for JsArrayBufferValue {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.data.as_slice()
self.as_ref()
}
}
impl DerefMut for JsArrayBufferValue {
fn deref_mut(&mut self) -> &mut Self::Target {
self.data.as_mut_slice()
self.as_mut()
}
}
@ -218,7 +225,7 @@ impl JsTypedArray {
&mut len as *mut u64 as *mut _,
&mut data,
&mut arraybuffer_value,
&mut byte_offset as *mut u64 as *mut _,
&mut byte_offset as *mut u64 as *mut usize,
)
})?;
@ -232,26 +239,34 @@ impl JsTypedArray {
}
}
impl JsTypedArrayValue {
#[inline(always)]
fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.data as *const u8, self.length as usize) }
}
macro_rules! impl_as_ref {
($ref_type:ident) => {
impl AsRef<[$ref_type]> for JsTypedArrayValue {
fn as_ref(&self) -> &[$ref_type] {
unsafe { slice::from_raw_parts(self.data as *const $ref_type, self.length as usize) }
}
}
impl AsMut<[$ref_type]> for JsTypedArrayValue {
fn as_mut(&mut self) -> &mut [$ref_type] {
unsafe { slice::from_raw_parts_mut(self.data as *mut $ref_type, self.length as usize) }
}
}
};
}
impl AsRef<[u8]> for JsTypedArrayValue {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl Deref for JsTypedArrayValue {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.as_slice()
}
}
impl_as_ref!(u8);
impl_as_ref!(i8);
impl_as_ref!(u16);
impl_as_ref!(i16);
impl_as_ref!(u32);
impl_as_ref!(i32);
impl_as_ref!(f32);
impl_as_ref!(f64);
#[cfg(feature = "napi6")]
impl_as_ref!(i64);
#[cfg(feature = "napi6")]
impl_as_ref!(u64);
impl JsDataView {
#[inline]

View file

@ -98,7 +98,9 @@ pub mod TypedarrayType {
pub const napi_uint32_array: i32 = 6;
pub const napi_float32_array: i32 = 7;
pub const napi_float64_array: i32 = 8;
#[cfg(feature = "napi6")]
pub const napi_bigint64_array: i32 = 9;
#[cfg(feature = "napi6")]
pub const napi_biguint64_array: i32 = 10;
}

View file

@ -1,8 +1,48 @@
import test from 'ava'
import ava from 'ava'
import { napiVersion } from './napi-version'
const bindings = require('../index.node')
const test = napiVersion >= 6 ? ava : ava.skip
test('should get arraybuffer length', (t) => {
const fixture = Buffer.from('wow, hello')
t.is(bindings.getArraybufferLength(fixture.buffer), fixture.buffer.byteLength)
})
test('should be able to mutate Uint8Array', (t) => {
const fixture = new Uint8Array([0, 1, 2])
bindings.mutateUint8Array(fixture)
t.is(fixture[0], 42)
})
test('should be able to mutate Uint16Array', (t) => {
const fixture = new Uint16Array([0, 1, 2])
bindings.mutateUint16Array(fixture)
t.is(fixture[0], 65535)
})
test('should be able to mutate Int16Array', (t) => {
const fixture = new Int16Array([0, 1, 2])
bindings.mutateInt16Array(fixture)
t.is(fixture[0], 32767)
})
test('should be able to mutate Float32Array', (t) => {
const fixture = new Float32Array([0, 1, 2])
bindings.mutateFloat32Array(fixture)
t.true(Math.abs(fixture[0] - 3.14) <= 0.0001)
})
test('should be able to mutate Float64Array', (t) => {
const fixture = new Float64Array([0, 1, 2])
bindings.mutateFloat64Array(fixture)
t.true(Math.abs(fixture[0] - Math.PI) <= 0.0000001)
})
test('should be able to mutate BigInt64Array', (t) => {
const fixture = new BigInt64Array([BigInt(0), BigInt(1), BigInt(2)])
bindings.mutateI64Array(fixture)
t.deepEqual(fixture[0], BigInt('9223372036854775807'))
})

View file

@ -1,6 +1,7 @@
use std::f64::consts::PI;
use std::str;
use napi::{CallContext, JsArrayBuffer, JsNumber, JsObject, Result};
use napi::{CallContext, JsArrayBuffer, JsNumber, JsObject, JsTypedArray, JsUndefined, Result};
#[js_function(1)]
pub fn get_arraybuffer_length(ctx: CallContext) -> Result<JsNumber> {
@ -8,7 +9,63 @@ pub fn get_arraybuffer_length(ctx: CallContext) -> Result<JsNumber> {
ctx.env.create_uint32((&buffer).len() as u32)
}
#[js_function(1)]
pub fn mutate_uint8_array(ctx: CallContext) -> Result<JsUndefined> {
let mut buffer = ctx.get::<JsTypedArray>(0)?.into_value()?;
let buffer_mut_ref: &mut [u8] = buffer.as_mut();
buffer_mut_ref[0] = 42;
ctx.env.get_undefined()
}
#[js_function(1)]
pub fn mutate_uint16_array(ctx: CallContext) -> Result<JsUndefined> {
let mut buffer = ctx.get::<JsTypedArray>(0)?.into_value()?;
let buffer_mut_ref: &mut [u16] = buffer.as_mut();
buffer_mut_ref[0] = 65535;
ctx.env.get_undefined()
}
#[js_function(1)]
pub fn mutate_int16_array(ctx: CallContext) -> Result<JsUndefined> {
let mut buffer = ctx.get::<JsTypedArray>(0)?.into_value()?;
let buffer_mut_ref: &mut [i16] = buffer.as_mut();
buffer_mut_ref[0] = 32767;
ctx.env.get_undefined()
}
#[js_function(1)]
pub fn mutate_float32_array(ctx: CallContext) -> Result<JsUndefined> {
let mut buffer = ctx.get::<JsTypedArray>(0)?.into_value()?;
let buffer_mut_ref: &mut [f32] = buffer.as_mut();
buffer_mut_ref[0] = 3.14;
ctx.env.get_undefined()
}
#[js_function(1)]
pub fn mutate_float64_array(ctx: CallContext) -> Result<JsUndefined> {
let mut buffer = ctx.get::<JsTypedArray>(0)?.into_value()?;
let buffer_mut_ref: &mut [f64] = buffer.as_mut();
buffer_mut_ref[0] = PI;
ctx.env.get_undefined()
}
#[js_function(1)]
#[cfg(feature = "latest")]
pub fn mutate_i64_array(ctx: CallContext) -> Result<JsUndefined> {
let mut buffer = ctx.get::<JsTypedArray>(0)?.into_value()?;
let buffer_mut_ref: &mut [i64] = buffer.as_mut();
buffer_mut_ref[0] = 9223372036854775807;
ctx.env.get_undefined()
}
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("getArraybufferLength", get_arraybuffer_length)?;
exports.create_named_method("mutateUint8Array", mutate_uint8_array)?;
exports.create_named_method("mutateUint16Array", mutate_uint16_array)?;
exports.create_named_method("mutateInt16Array", mutate_int16_array)?;
exports.create_named_method("mutateFloat32Array", mutate_float32_array)?;
exports.create_named_method("mutateFloat64Array", mutate_float64_array)?;
#[cfg(feature = "latest")]
exports.create_named_method("mutateI64Array", mutate_i64_array)?;
Ok(())
}