Merge pull request #578 from napi-rs/arraybuffer
feat(napi): impl more types AsRef and AsMut for TypedArray
This commit is contained in:
commit
b707d9bb82
5 changed files with 157 additions and 39 deletions
|
@ -417,7 +417,8 @@ impl Env {
|
||||||
|
|
||||||
Ok(JsArrayBufferValue::new(
|
Ok(JsArrayBufferValue::new(
|
||||||
unsafe { JsArrayBuffer::from_raw_unchecked(self.0, raw_value) },
|
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(
|
Ok(JsArrayBufferValue::new(
|
||||||
JsArrayBuffer(Value {
|
JsArrayBuffer(Value {
|
||||||
env: self.0,
|
env: self.0,
|
||||||
value: raw_value,
|
value: raw_value,
|
||||||
value_type: ValueType::Object,
|
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: raw_value,
|
||||||
value_type: ValueType::Object,
|
value_type: ValueType::Object,
|
||||||
}),
|
}),
|
||||||
mem::ManuallyDrop::new(Vec::from_raw_parts(data as *mut u8, length, length)),
|
data as *mut c_void,
|
||||||
|
length,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use std::mem;
|
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
@ -10,7 +9,8 @@ pub struct JsArrayBuffer(pub(crate) Value);
|
||||||
|
|
||||||
pub struct JsArrayBufferValue {
|
pub struct JsArrayBufferValue {
|
||||||
pub(crate) value: JsArrayBuffer,
|
pub(crate) value: JsArrayBuffer,
|
||||||
data: mem::ManuallyDrop<Vec<u8>>,
|
len: usize,
|
||||||
|
data: *mut c_void,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct JsTypedArray(pub(crate) Value);
|
pub struct JsTypedArray(pub(crate) Value);
|
||||||
|
@ -34,6 +34,7 @@ pub struct JsDataViewValue {
|
||||||
|
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
#[non_exhaustive]
|
||||||
pub enum TypedArrayType {
|
pub enum TypedArrayType {
|
||||||
Int8 = 0,
|
Int8 = 0,
|
||||||
Uint8,
|
Uint8,
|
||||||
|
@ -44,7 +45,9 @@ pub enum TypedArrayType {
|
||||||
Uint32,
|
Uint32,
|
||||||
Float32,
|
Float32,
|
||||||
Float64,
|
Float64,
|
||||||
|
#[cfg(feature = "napi6")]
|
||||||
BigInt64,
|
BigInt64,
|
||||||
|
#[cfg(feature = "napi6")]
|
||||||
BigUint64,
|
BigUint64,
|
||||||
|
|
||||||
/// compatible with higher versions
|
/// 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_uint32_array => Self::Uint32,
|
||||||
sys::TypedarrayType::napi_float32_array => Self::Float32,
|
sys::TypedarrayType::napi_float32_array => Self::Float32,
|
||||||
sys::TypedarrayType::napi_float64_array => Self::Float64,
|
sys::TypedarrayType::napi_float64_array => Self::Float64,
|
||||||
|
#[cfg(feature = "napi6")]
|
||||||
sys::TypedarrayType::napi_bigint64_array => Self::BigInt64,
|
sys::TypedarrayType::napi_bigint64_array => Self::BigInt64,
|
||||||
|
#[cfg(feature = "napi6")]
|
||||||
sys::TypedarrayType::napi_biguint64_array => Self::BigUint64,
|
sys::TypedarrayType::napi_biguint64_array => Self::BigUint64,
|
||||||
_ => Self::Unknown,
|
_ => Self::Unknown,
|
||||||
}
|
}
|
||||||
|
@ -72,7 +77,7 @@ impl From<sys::napi_typedarray_type> for TypedArrayType {
|
||||||
|
|
||||||
impl From<TypedArrayType> for sys::napi_typedarray_type {
|
impl From<TypedArrayType> for sys::napi_typedarray_type {
|
||||||
fn from(value: TypedArrayType) -> 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 data = ptr::null_mut();
|
||||||
let mut len: usize = 0;
|
let mut len: usize = 0;
|
||||||
check_status!(unsafe {
|
check_status!(unsafe {
|
||||||
sys::napi_get_arraybuffer_info(
|
sys::napi_get_arraybuffer_info(self.0.env, self.0.value, &mut data, &mut len as *mut usize)
|
||||||
self.0.env,
|
|
||||||
self.0.value,
|
|
||||||
&mut data,
|
|
||||||
&mut len as *mut usize as *mut _,
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
Ok(JsArrayBufferValue {
|
Ok(JsArrayBufferValue {
|
||||||
data: mem::ManuallyDrop::new(unsafe { Vec::from_raw_parts(data as *mut _, len, len) }),
|
data,
|
||||||
value: self,
|
value: self,
|
||||||
|
len,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,8 +164,8 @@ impl JsArrayBuffer {
|
||||||
|
|
||||||
impl JsArrayBufferValue {
|
impl JsArrayBufferValue {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(value: JsArrayBuffer, data: mem::ManuallyDrop<Vec<u8>>) -> Self {
|
pub fn new(value: JsArrayBuffer, data: *mut c_void, len: usize) -> Self {
|
||||||
JsArrayBufferValue { value, data }
|
JsArrayBufferValue { value, len, data }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -180,7 +181,13 @@ impl JsArrayBufferValue {
|
||||||
|
|
||||||
impl AsRef<[u8]> for JsArrayBufferValue {
|
impl AsRef<[u8]> for JsArrayBufferValue {
|
||||||
fn as_ref(&self) -> &[u8] {
|
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];
|
type Target = [u8];
|
||||||
|
|
||||||
fn deref(&self) -> &[u8] {
|
fn deref(&self) -> &[u8] {
|
||||||
self.data.as_slice()
|
self.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for JsArrayBufferValue {
|
impl DerefMut for JsArrayBufferValue {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
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 len as *mut u64 as *mut _,
|
||||||
&mut data,
|
&mut data,
|
||||||
&mut arraybuffer_value,
|
&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 {
|
macro_rules! impl_as_ref {
|
||||||
#[inline(always)]
|
($ref_type:ident) => {
|
||||||
fn as_slice(&self) -> &[u8] {
|
impl AsRef<[$ref_type]> for JsTypedArrayValue {
|
||||||
unsafe { slice::from_raw_parts(self.data as *const u8, self.length as usize) }
|
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 {
|
impl_as_ref!(u8);
|
||||||
fn as_ref(&self) -> &[u8] {
|
impl_as_ref!(i8);
|
||||||
self.as_slice()
|
impl_as_ref!(u16);
|
||||||
}
|
impl_as_ref!(i16);
|
||||||
}
|
impl_as_ref!(u32);
|
||||||
|
impl_as_ref!(i32);
|
||||||
impl Deref for JsTypedArrayValue {
|
impl_as_ref!(f32);
|
||||||
type Target = [u8];
|
impl_as_ref!(f64);
|
||||||
|
#[cfg(feature = "napi6")]
|
||||||
fn deref(&self) -> &[u8] {
|
impl_as_ref!(i64);
|
||||||
self.as_slice()
|
#[cfg(feature = "napi6")]
|
||||||
}
|
impl_as_ref!(u64);
|
||||||
}
|
|
||||||
|
|
||||||
impl JsDataView {
|
impl JsDataView {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -98,7 +98,9 @@ pub mod TypedarrayType {
|
||||||
pub const napi_uint32_array: i32 = 6;
|
pub const napi_uint32_array: i32 = 6;
|
||||||
pub const napi_float32_array: i32 = 7;
|
pub const napi_float32_array: i32 = 7;
|
||||||
pub const napi_float64_array: i32 = 8;
|
pub const napi_float64_array: i32 = 8;
|
||||||
|
#[cfg(feature = "napi6")]
|
||||||
pub const napi_bigint64_array: i32 = 9;
|
pub const napi_bigint64_array: i32 = 9;
|
||||||
|
#[cfg(feature = "napi6")]
|
||||||
pub const napi_biguint64_array: i32 = 10;
|
pub const napi_biguint64_array: i32 = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,48 @@
|
||||||
import test from 'ava'
|
import ava from 'ava'
|
||||||
|
|
||||||
|
import { napiVersion } from './napi-version'
|
||||||
|
|
||||||
const bindings = require('../index.node')
|
const bindings = require('../index.node')
|
||||||
|
|
||||||
|
const test = napiVersion >= 6 ? ava : ava.skip
|
||||||
|
|
||||||
test('should get arraybuffer length', (t) => {
|
test('should get arraybuffer length', (t) => {
|
||||||
const fixture = Buffer.from('wow, hello')
|
const fixture = Buffer.from('wow, hello')
|
||||||
t.is(bindings.getArraybufferLength(fixture.buffer), fixture.buffer.byteLength)
|
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'))
|
||||||
|
})
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
use std::f64::consts::PI;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use napi::{CallContext, JsArrayBuffer, JsNumber, JsObject, Result};
|
use napi::{CallContext, JsArrayBuffer, JsNumber, JsObject, JsTypedArray, JsUndefined, Result};
|
||||||
|
|
||||||
#[js_function(1)]
|
#[js_function(1)]
|
||||||
pub fn get_arraybuffer_length(ctx: CallContext) -> Result<JsNumber> {
|
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)
|
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<()> {
|
pub fn register_js(exports: &mut JsObject) -> Result<()> {
|
||||||
exports.create_named_method("getArraybufferLength", get_arraybuffer_length)?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue