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(
|
||||
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,
|
||||
))
|
||||
}
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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'))
|
||||
})
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue