Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions crates/neon/src/types_impl/buffer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
result::{JsResult, NeonResult, ResultExt},
types::{
buffer::lock::{Ledger, Lock},
JsArrayBuffer, JsTypedArray,
JsArrayBuffer, JsTypedArray, Value,
},
};

Expand Down Expand Up @@ -47,7 +47,7 @@ pub use types::Binary;
/// ```
///
/// [typed-arrays]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
pub trait TypedArray: private::Sealed {
pub trait TypedArray: Value {
type Item: Binary;

/// Statically checked immutable borrow of binary data.
Expand Down Expand Up @@ -93,6 +93,11 @@ pub trait TypedArray: private::Sealed {
fn size<'cx, C>(&self, cx: &mut C) -> usize
where
C: Context<'cx>;

/// Constructs an instance from a slice by copying its contents.
fn from_slice<'cx, C>(cx: &mut C, slice: &[Self::Item]) -> JsResult<'cx, Self>
where
C: Context<'cx>;
}

#[derive(Debug)]
Expand Down
82 changes: 80 additions & 2 deletions crates/neon/src/types_impl/buffer/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ impl JsBuffer {
}
}

/// Constructs a `JsBuffer` from a slice by copying its contents.
///
/// This method is defined on `JsBuffer` as a convenience and delegates to
/// [`TypedArray::from_slice`][TypedArray::from_slice].
pub fn from_slice<'cx, C>(cx: &mut C, slice: &[u8]) -> JsResult<'cx, Self>
where
C: Context<'cx>,
{
<JsBuffer as TypedArray>::from_slice(cx, slice)
}

/// Constructs a new `Buffer` object with uninitialized memory
pub unsafe fn uninitialized<'a, C: Context<'a>>(cx: &mut C, len: usize) -> JsResult<'a, Self> {
let result = sys::buffer::uninitialized(cx.env().to_raw(), len);
Expand Down Expand Up @@ -169,6 +180,16 @@ impl TypedArray for JsBuffer {
fn size<'cx, C: Context<'cx>>(&self, cx: &mut C) -> usize {
unsafe { sys::buffer::size(cx.env().to_raw(), self.to_raw()) }
}

fn from_slice<'cx, C>(cx: &mut C, slice: &[u8]) -> JsResult<'cx, Self>
where
C: Context<'cx>,
{
let mut buffer = cx.buffer(slice.len())?;
let target = buffer.as_mut_slice(cx);
target.copy_from_slice(slice);
Ok(buffer)
}
}

/// The standard JS [`ArrayBuffer`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) type.
Expand Down Expand Up @@ -206,6 +227,17 @@ impl JsArrayBuffer {
}
}

/// Constructs a `JsArrayBuffer` from a slice by copying its contents.
///
/// This method is defined on `JsArrayBuffer` as a convenience and delegates to
/// [`TypedArray::from_slice`][TypedArray::from_slice].
pub fn from_slice<'cx, C>(cx: &mut C, slice: &[u8]) -> JsResult<'cx, Self>
where
C: Context<'cx>,
{
<JsArrayBuffer as TypedArray>::from_slice(cx, slice)
}

/// Construct a new `JsArrayBuffer` from bytes allocated by Rust
pub fn external<'a, C, T>(cx: &mut C, data: T) -> Handle<'a, Self>
where
Expand Down Expand Up @@ -339,12 +371,23 @@ impl TypedArray for JsArrayBuffer {
fn size<'cx, C: Context<'cx>>(&self, cx: &mut C) -> usize {
unsafe { sys::arraybuffer::size(cx.env().to_raw(), self.to_raw()) }
}

fn from_slice<'cx, C>(cx: &mut C, slice: &[u8]) -> JsResult<'cx, Self>
where
C: Context<'cx>,
{
let len = slice.len();
let mut buffer = JsArrayBuffer::new(cx, len)?;
let target = buffer.as_mut_slice(cx);
target.copy_from_slice(slice);
Ok(buffer)
}
}

/// A marker trait for all possible element types of binary buffers.
///
/// This trait can only be implemented within the Neon library.
pub trait Binary: private::Sealed + Clone {
pub trait Binary: private::Sealed + Copy {
/// The internal Node-API enum value for this binary type.
const TYPE_TAG: TypedArrayType;
}
Expand Down Expand Up @@ -475,7 +518,11 @@ impl<T: Binary> Managed for JsTypedArray<T> {
}
}

impl<T: Binary> TypedArray for JsTypedArray<T> {
impl<T> TypedArray for JsTypedArray<T>
where
T: Binary,
Self: Value,
{
type Item = T;

fn as_slice<'cx, 'a, C>(&self, cx: &'a C) -> &'a [Self::Item]
Expand Down Expand Up @@ -547,6 +594,37 @@ impl<T: Binary> TypedArray for JsTypedArray<T> {
fn size<'cx, C: Context<'cx>>(&self, cx: &mut C) -> usize {
self.len(cx) * std::mem::size_of::<Self::Item>()
}

fn from_slice<'cx, C>(cx: &mut C, slice: &[T]) -> JsResult<'cx, Self>
where
C: Context<'cx>,
{
let elt_size = std::mem::size_of::<T>();
let size = slice.len() * elt_size;
let buffer = cx.array_buffer(size)?;

let mut array = Self::from_buffer(cx, buffer)?;
let target = array.as_mut_slice(cx);
target.copy_from_slice(slice);

Ok(array)
}
}

impl<T: Binary> JsTypedArray<T>
where
JsTypedArray<T>: Value,
{
/// Constructs an instance from a slice by copying its contents.
///
/// This method is defined on `JsTypedArray` as a convenience and delegates to
/// [`TypedArray::from_slice`][TypedArray::from_slice].
pub fn from_slice<'cx, C>(cx: &mut C, slice: &[T]) -> JsResult<'cx, Self>
where
C: Context<'cx>,
{
<JsTypedArray<T> as TypedArray>::from_slice(cx, slice)
}
}

impl<T: Binary> JsTypedArray<T> {
Expand Down
15 changes: 15 additions & 0 deletions test/napi/lib/typedarrays.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,14 @@ describe("Typed arrays", function () {
assert.ok(b.equals(Buffer.alloc(16)));
});

it("gets a 16-byte buffer initialized from a slice", function () {
var b = addon.return_array_buffer_from_slice(16);
var a = new Uint8Array(b);
for (var i = 0; i < 16; i++) {
assert.strictEqual(a[i], i);
}
});

it("gets an external Buffer", function () {
var expected = "String to copy";
var buf = addon.return_external_buffer(expected);
Expand Down Expand Up @@ -242,6 +250,13 @@ describe("Typed arrays", function () {
);
});

it("gets a typed array copied from a slice", function () {
var i32 = addon.return_int32array_from_slice(16);
for (var i = 0; i < 16; i++) {
assert.strictEqual(i32[i], i);
}
});

it("gets correct typed array info", function () {
var buf = new ArrayBuffer(128);

Expand Down
20 changes: 20 additions & 0 deletions test/napi/src/js/typedarrays.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ pub fn return_array_buffer(mut cx: FunctionContext) -> JsResult<JsArrayBuffer> {
Ok(b)
}

pub fn return_array_buffer_from_slice(mut cx: FunctionContext) -> JsResult<JsArrayBuffer> {
let len = cx.argument::<JsNumber>(0)?.value(&mut cx) as usize;
let v = (0..len).map(|i| i as u8).collect::<Vec<_>>();

JsArrayBuffer::from_slice(&mut cx, &v)
}

pub fn read_array_buffer_with_lock(mut cx: FunctionContext) -> JsResult<JsNumber> {
let buf = cx.argument::<JsTypedArray<u32>>(0)?;
let i = cx.argument::<JsNumber>(1)?.value(&mut cx) as usize;
Expand Down Expand Up @@ -150,6 +157,18 @@ pub fn return_new_int32array(mut cx: FunctionContext) -> JsResult<JsInt32Array>
JsInt32Array::new(&mut cx, len)
}

pub fn return_int32array_from_slice(mut cx: FunctionContext) -> JsResult<JsInt32Array> {
let len: Handle<JsNumber> = cx.argument(0)?;
let len: f64 = len.value(&mut cx);
let len: u32 = len as u32;
let mut v: Vec<i32> = Vec::new();
for i in 0..len {
v.push(i as i32);
}
let a: Handle<JsInt32Array> = JsInt32Array::from_slice(&mut cx, &v)?;
Ok(a)
}

pub fn return_uint32array_from_arraybuffer_region(
mut cx: FunctionContext,
) -> JsResult<JsUint32Array> {
Expand All @@ -174,6 +193,7 @@ fn typed_array_info<'cx, C, T: Binary>(
) -> JsResult<'cx, JsObject>
where
C: Context<'cx>,
JsTypedArray<T>: Value,
{
let offset = a.offset(cx);
let offset = cx.number(offset as u32);
Expand Down
5 changes: 5 additions & 0 deletions test/napi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> {
cx.export_function("seal_js_object", seal_js_object)?;

cx.export_function("return_array_buffer", return_array_buffer)?;
cx.export_function(
"return_array_buffer_from_slice",
return_array_buffer_from_slice,
)?;
cx.export_function("read_array_buffer_with_lock", read_array_buffer_with_lock)?;
cx.export_function(
"read_array_buffer_with_borrow",
Expand Down Expand Up @@ -254,6 +258,7 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> {
return_biguint64array_from_arraybuffer,
)?;
cx.export_function("return_new_int32array", return_new_int32array)?;
cx.export_function("return_int32array_from_slice", return_int32array_from_slice)?;
cx.export_function(
"return_uint32array_from_arraybuffer_region",
return_uint32array_from_arraybuffer_region,
Expand Down