feat(napi): accept slice as TypedArray (#1951)
This commit is contained in:
parent
d7dc4dc5a2
commit
5ac153388f
8 changed files with 244 additions and 12 deletions
|
@ -268,7 +268,7 @@ impl NapiFn {
|
|||
if let Some(p) = path.path.segments.first() {
|
||||
if p.ident == *self.parent.as_ref().unwrap() {
|
||||
args.push(
|
||||
quote! { napi::bindgen_prelude::Reference::from_value_ptr(this_ptr as *mut std::ffi::c_void, env)? },
|
||||
quote! { napi::bindgen_prelude::Reference::from_value_ptr(this_ptr.cast(), env)? },
|
||||
);
|
||||
skipped_arg_count += 1;
|
||||
continue;
|
||||
|
@ -344,7 +344,7 @@ impl NapiFn {
|
|||
}
|
||||
}
|
||||
}
|
||||
let (arg_conversion, arg_type) = self.gen_ty_arg_conversion(&ident, i, path);
|
||||
let (arg_conversion, arg_type) = self.gen_ty_arg_conversion(&ident, i, path)?;
|
||||
if NapiArgType::MutRef == arg_type {
|
||||
mut_ref_spans.push(path.ty.span());
|
||||
}
|
||||
|
@ -378,7 +378,7 @@ impl NapiFn {
|
|||
arg_name: &Ident,
|
||||
index: usize,
|
||||
path: &syn::PatType,
|
||||
) -> (TokenStream, NapiArgType) {
|
||||
) -> BindgenResult<(TokenStream, NapiArgType)> {
|
||||
let ty = &*path.ty;
|
||||
let type_check = if self.return_if_invalid {
|
||||
quote! {
|
||||
|
@ -402,6 +402,15 @@ impl NapiFn {
|
|||
};
|
||||
|
||||
match ty {
|
||||
syn::Type::Reference(syn::TypeReference {
|
||||
lifetime: Some(lifetime),
|
||||
..
|
||||
}) => {
|
||||
return Err(Diagnostic::span_error(
|
||||
lifetime.span(),
|
||||
"lifetime is not allowed in napi function arguments",
|
||||
));
|
||||
}
|
||||
syn::Type::Reference(syn::TypeReference {
|
||||
mutability: Some(_),
|
||||
elem,
|
||||
|
@ -413,16 +422,52 @@ impl NapiFn {
|
|||
<#elem as napi::bindgen_prelude::FromNapiMutRef>::from_napi_mut_ref(env, cb.get_arg(#index))?
|
||||
};
|
||||
};
|
||||
(q, NapiArgType::MutRef)
|
||||
Ok((q, NapiArgType::MutRef))
|
||||
}
|
||||
syn::Type::Reference(syn::TypeReference { elem, .. }) => {
|
||||
let q = quote! {
|
||||
let #arg_name = {
|
||||
#type_check
|
||||
<#elem as napi::bindgen_prelude::FromNapiRef>::from_napi_ref(env, cb.get_arg(#index))?
|
||||
};
|
||||
syn::Type::Reference(syn::TypeReference {
|
||||
mutability, elem, ..
|
||||
}) => {
|
||||
if let syn::Type::Slice(slice) = &**elem {
|
||||
if let syn::Type::Path(ele) = &*slice.elem {
|
||||
if let Some(syn::PathSegment { ident, .. }) = ele.path.segments.first() {
|
||||
static TYPEDARRAY_SLICE_TYPES: &[&str] = &[
|
||||
"u8", "i8", "u16", "i16", "u32", "i32", "f32", "f64", "u64", "i64",
|
||||
];
|
||||
if TYPEDARRAY_SLICE_TYPES.contains(&&*ident.to_string()) {
|
||||
let q = quote! {
|
||||
let #arg_name = {
|
||||
#type_check
|
||||
<&mut #elem as napi::bindgen_prelude::FromNapiValue>::from_napi_value(env, cb.get_arg(#index))?
|
||||
};
|
||||
};
|
||||
return Ok((q, NapiArgType::Ref));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let q = if mutability.is_some() {
|
||||
quote! {
|
||||
let #arg_name = {
|
||||
#type_check
|
||||
<#elem as napi::bindgen_prelude::FromNapiMutRef>::from_napi_mut_ref(env, cb.get_arg(#index))?
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
let #arg_name = {
|
||||
#type_check
|
||||
<#elem as napi::bindgen_prelude::FromNapiRef>::from_napi_ref(env, cb.get_arg(#index))?
|
||||
};
|
||||
}
|
||||
};
|
||||
(q, NapiArgType::Ref)
|
||||
Ok((
|
||||
q,
|
||||
if mutability.is_some() {
|
||||
NapiArgType::MutRef
|
||||
} else {
|
||||
NapiArgType::Ref
|
||||
},
|
||||
))
|
||||
}
|
||||
_ => {
|
||||
let q = quote! {
|
||||
|
@ -431,7 +476,7 @@ impl NapiFn {
|
|||
<#ty as napi::bindgen_prelude::FromNapiValue>::from_napi_value(env, cb.get_arg(#index))?
|
||||
};
|
||||
};
|
||||
(q, NapiArgType::Value)
|
||||
Ok((q, NapiArgType::Value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -457,6 +457,46 @@ macro_rules! impl_typed_array {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_from_slice {
|
||||
($name:ident, $rust_type:ident, $typed_array_type:expr) => {
|
||||
impl FromNapiValue for &mut [$rust_type] {
|
||||
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
|
||||
let mut typed_array_type = 0;
|
||||
let mut length = 0;
|
||||
let mut data = ptr::null_mut();
|
||||
let mut array_buffer = ptr::null_mut();
|
||||
let mut byte_offset = 0;
|
||||
let mut ref_ = ptr::null_mut();
|
||||
check_status!(
|
||||
unsafe { sys::napi_create_reference(env, napi_val, 1, &mut ref_) },
|
||||
"Failed to create reference from Buffer"
|
||||
)?;
|
||||
check_status!(
|
||||
unsafe {
|
||||
sys::napi_get_typedarray_info(
|
||||
env,
|
||||
napi_val,
|
||||
&mut typed_array_type,
|
||||
&mut length,
|
||||
&mut data,
|
||||
&mut array_buffer,
|
||||
&mut byte_offset,
|
||||
)
|
||||
},
|
||||
"Get TypedArray info failed"
|
||||
)?;
|
||||
if typed_array_type != $typed_array_type as i32 {
|
||||
return Err(Error::new(
|
||||
Status::InvalidArg,
|
||||
format!("Expected $name, got {}", typed_array_type),
|
||||
));
|
||||
}
|
||||
Ok(unsafe { core::slice::from_raw_parts_mut(data as *mut $rust_type, length) })
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
unsafe extern "C" fn finalizer<Data, T: Finalizer<RustType = Data>>(
|
||||
_env: sys::napi_env,
|
||||
finalize_data: *mut c_void,
|
||||
|
@ -494,18 +534,30 @@ enum DataManagedType {
|
|||
}
|
||||
|
||||
impl_typed_array!(Int8Array, i8, TypedArrayType::Int8);
|
||||
impl_from_slice!(Int8Array, i8, TypedArrayType::Int8);
|
||||
impl_typed_array!(Uint8Array, u8, TypedArrayType::Uint8);
|
||||
impl_from_slice!(Uint8Array, u8, TypedArrayType::Uint8);
|
||||
impl_typed_array!(Uint8ClampedArray, u8, TypedArrayType::Uint8Clamped);
|
||||
impl_typed_array!(Int16Array, i16, TypedArrayType::Int16);
|
||||
impl_from_slice!(Int16Array, i16, TypedArrayType::Int16);
|
||||
impl_typed_array!(Uint16Array, u16, TypedArrayType::Uint16);
|
||||
impl_from_slice!(Uint16Array, u16, TypedArrayType::Uint16);
|
||||
impl_typed_array!(Int32Array, i32, TypedArrayType::Int32);
|
||||
impl_from_slice!(Int32Array, i32, TypedArrayType::Int32);
|
||||
impl_typed_array!(Uint32Array, u32, TypedArrayType::Uint32);
|
||||
impl_from_slice!(Uint32Array, u32, TypedArrayType::Uint32);
|
||||
impl_typed_array!(Float32Array, f32, TypedArrayType::Float32);
|
||||
impl_from_slice!(Float32Array, f32, TypedArrayType::Float32);
|
||||
impl_typed_array!(Float64Array, f64, TypedArrayType::Float64);
|
||||
impl_from_slice!(Float64Array, f64, TypedArrayType::Float64);
|
||||
#[cfg(feature = "napi6")]
|
||||
impl_typed_array!(BigInt64Array, i64, TypedArrayType::BigInt64);
|
||||
#[cfg(feature = "napi6")]
|
||||
impl_from_slice!(BigInt64Array, i64, TypedArrayType::BigInt64);
|
||||
#[cfg(feature = "napi6")]
|
||||
impl_typed_array!(BigUint64Array, u64, TypedArrayType::BigUint64);
|
||||
#[cfg(feature = "napi6")]
|
||||
impl_from_slice!(BigUint64Array, u64, TypedArrayType::BigUint64);
|
||||
|
||||
impl<T: Into<Vec<u8>>> From<T> for Uint8Array {
|
||||
fn from(data: T) -> Self {
|
||||
|
|
|
@ -85,6 +85,7 @@ Generated by [AVA](https://avajs.dev).
|
|||
constructor(name: string)␊
|
||||
getCount(): number␊
|
||||
getNameAsync(): Promise<string>␊
|
||||
acceptSliceMethod(slice: any): number␊
|
||||
}␊
|
||||
␊
|
||||
/** Smoking test for type generation */␊
|
||||
|
@ -221,6 +222,8 @@ Generated by [AVA](https://avajs.dev).
|
|||
foo: number␊
|
||||
}␊
|
||||
␊
|
||||
export function acceptSlice(fixture: any): bigint␊
|
||||
␊
|
||||
export function acceptThreadsafeFunction(func: (err: Error | null, arg: number) => any): void␊
|
||||
␊
|
||||
export function acceptThreadsafeFunctionFatal(func: (arg: number) => any): void␊
|
||||
|
@ -388,6 +391,10 @@ Generated by [AVA](https://avajs.dev).
|
|||
␊
|
||||
export function enumToI32(e: CustomNumEnum): number␊
|
||||
␊
|
||||
export function f32ArrayToArray(input: any): Array<number>␊
|
||||
␊
|
||||
export function f64ArrayToArray(input: any): Array<number>␊
|
||||
␊
|
||||
export function fibonacci(n: number): number␊
|
||||
␊
|
||||
export function fnReceivedAliased(s: AliasedStruct, e: ALIAS): void␊
|
||||
|
@ -429,6 +436,14 @@ Generated by [AVA](https://avajs.dev).
|
|||
␊
|
||||
export function getWords(): Array<string>␊
|
||||
␊
|
||||
export function i16ArrayToArray(input: any): Array<number>␊
|
||||
␊
|
||||
export function i32ArrayToArray(input: any): Array<number>␊
|
||||
␊
|
||||
export function i64ArrayToArray(input: any): Array<number>␊
|
||||
␊
|
||||
export function i8ArrayToArray(input: any): Array<number>␊
|
||||
␊
|
||||
export function indexmapPassthrough(fixture: IndexMap): IndexMap␊
|
||||
␊
|
||||
/** default enum values are continuos i32s start from 0 */␊
|
||||
|
@ -595,6 +610,14 @@ Generated by [AVA](https://avajs.dev).
|
|||
typeOverrideOptional?: object␊
|
||||
}␊
|
||||
␊
|
||||
export function u16ArrayToArray(input: any): Array<number>␊
|
||||
␊
|
||||
export function u32ArrayToArray(input: any): Array<number>␊
|
||||
␊
|
||||
export function u64ArrayToArray(input: any): Array<bigint>␊
|
||||
␊
|
||||
export function u8ArrayToArray(input: any): Array<number>␊
|
||||
␊
|
||||
export function validateArray(arr: Array<number>): number␊
|
||||
␊
|
||||
export function validateBigint(input: bigint): bigint␊
|
||||
|
|
Binary file not shown.
|
@ -94,6 +94,17 @@ const {
|
|||
xxh3,
|
||||
xxh64Alias,
|
||||
tsRename,
|
||||
acceptSlice,
|
||||
u8ArrayToArray,
|
||||
i8ArrayToArray,
|
||||
u16ArrayToArray,
|
||||
i16ArrayToArray,
|
||||
u32ArrayToArray,
|
||||
i32ArrayToArray,
|
||||
u64ArrayToArray,
|
||||
i64ArrayToArray,
|
||||
f32ArrayToArray,
|
||||
f64ArrayToArray,
|
||||
convertU32Array,
|
||||
createExternalTypedArray,
|
||||
mutateTypedArray,
|
||||
|
@ -665,6 +676,24 @@ test('buffer', (t) => {
|
|||
t.true(Array.isArray(asyncBufferToArray(Buffer.from([1, 2, 3]).buffer)))
|
||||
})
|
||||
|
||||
test('TypedArray', (t) => {
|
||||
t.is(acceptSlice(new Uint8Array([1, 2, 3])), 3n)
|
||||
t.deepEqual(u8ArrayToArray(new Uint8Array([1, 2, 3])), [1, 2, 3])
|
||||
t.deepEqual(i8ArrayToArray(new Int8Array([1, 2, 3])), [1, 2, 3])
|
||||
t.deepEqual(u16ArrayToArray(new Uint16Array([1, 2, 3])), [1, 2, 3])
|
||||
t.deepEqual(i16ArrayToArray(new Int16Array([1, 2, 3])), [1, 2, 3])
|
||||
t.deepEqual(u32ArrayToArray(new Uint32Array([1, 2, 3])), [1, 2, 3])
|
||||
t.deepEqual(i32ArrayToArray(new Int32Array([1, 2, 3])), [1, 2, 3])
|
||||
t.deepEqual(u64ArrayToArray(new BigUint64Array([1n, 2n, 3n])), [1n, 2n, 3n])
|
||||
t.deepEqual(i64ArrayToArray(new BigInt64Array([1n, 2n, 3n])), [1, 2, 3])
|
||||
t.deepEqual(f32ArrayToArray(new Float32Array([1, 2, 3])), [1, 2, 3])
|
||||
t.deepEqual(f64ArrayToArray(new Float64Array([1, 2, 3])), [1, 2, 3])
|
||||
|
||||
const bird = new Bird('Carolyn')
|
||||
|
||||
t.is(bird.acceptSliceMethod(new Uint8Array([1, 2, 3])), 3)
|
||||
})
|
||||
|
||||
test('reset empty buffer', (t) => {
|
||||
const empty = getEmptyBuffer()
|
||||
|
||||
|
|
23
examples/napi/index.d.ts
vendored
23
examples/napi/index.d.ts
vendored
|
@ -75,6 +75,7 @@ export class Bird {
|
|||
constructor(name: string)
|
||||
getCount(): number
|
||||
getNameAsync(): Promise<string>
|
||||
acceptSliceMethod(slice: any): number
|
||||
}
|
||||
|
||||
/** Smoking test for type generation */
|
||||
|
@ -211,6 +212,8 @@ export interface A {
|
|||
foo: number
|
||||
}
|
||||
|
||||
export function acceptSlice(fixture: any): bigint
|
||||
|
||||
export function acceptThreadsafeFunction(func: (err: Error | null, arg: number) => any): void
|
||||
|
||||
export function acceptThreadsafeFunctionFatal(func: (arg: number) => any): void
|
||||
|
@ -378,6 +381,10 @@ export const enum Empty {
|
|||
|
||||
export function enumToI32(e: CustomNumEnum): number
|
||||
|
||||
export function f32ArrayToArray(input: any): Array<number>
|
||||
|
||||
export function f64ArrayToArray(input: any): Array<number>
|
||||
|
||||
export function fibonacci(n: number): number
|
||||
|
||||
export function fnReceivedAliased(s: AliasedStruct, e: ALIAS): void
|
||||
|
@ -419,6 +426,14 @@ export function getUndefined(): void
|
|||
|
||||
export function getWords(): Array<string>
|
||||
|
||||
export function i16ArrayToArray(input: any): Array<number>
|
||||
|
||||
export function i32ArrayToArray(input: any): Array<number>
|
||||
|
||||
export function i64ArrayToArray(input: any): Array<number>
|
||||
|
||||
export function i8ArrayToArray(input: any): Array<number>
|
||||
|
||||
export function indexmapPassthrough(fixture: IndexMap): IndexMap
|
||||
|
||||
/** default enum values are continuos i32s start from 0 */
|
||||
|
@ -585,6 +600,14 @@ export interface TsTypeChanged {
|
|||
typeOverrideOptional?: object
|
||||
}
|
||||
|
||||
export function u16ArrayToArray(input: any): Array<number>
|
||||
|
||||
export function u32ArrayToArray(input: any): Array<number>
|
||||
|
||||
export function u64ArrayToArray(input: any): Array<bigint>
|
||||
|
||||
export function u8ArrayToArray(input: any): Array<number>
|
||||
|
||||
export function validateArray(arr: Array<number>): number
|
||||
|
||||
export function validateBigint(input: bigint): bigint
|
||||
|
|
|
@ -130,6 +130,11 @@ impl Bird {
|
|||
tokio::time::sleep(std::time::Duration::new(1, 0)).await;
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub fn accept_slice_method(&self, slice: &[u8]) -> u32 {
|
||||
slice.len() as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// Smoking test for type generation
|
||||
|
|
|
@ -49,6 +49,61 @@ async fn array_buffer_pass_through(buf: Uint8Array) -> Result<Uint8Array> {
|
|||
Ok(buf)
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn accept_slice(fixture: &[u8]) -> usize {
|
||||
fixture.len()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn u8_array_to_array(input: &[u8]) -> Vec<u8> {
|
||||
input.to_vec()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn i8_array_to_array(input: &[i8]) -> Vec<i8> {
|
||||
input.to_vec()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn u16_array_to_array(input: &[u16]) -> Vec<u16> {
|
||||
input.to_vec()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn i16_array_to_array(input: &[i16]) -> Vec<i16> {
|
||||
input.to_vec()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn u32_array_to_array(input: &[u32]) -> Vec<u32> {
|
||||
input.to_vec()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn i32_array_to_array(input: &[i32]) -> Vec<i32> {
|
||||
input.to_vec()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn f32_array_to_array(input: &[f32]) -> Vec<f32> {
|
||||
input.to_vec()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn f64_array_to_array(input: &[f64]) -> Vec<f64> {
|
||||
input.to_vec()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn u64_array_to_array(input: &[u64]) -> Vec<u64> {
|
||||
input.to_vec()
|
||||
}
|
||||
|
||||
#[napi]
|
||||
fn i64_array_to_array(input: &[i64]) -> Vec<i64> {
|
||||
input.to_vec()
|
||||
}
|
||||
|
||||
struct AsyncBuffer {
|
||||
buf: Buffer,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue