rquickjs-napi 0.0.6

Node-API (N-API) support and native addon loading for rquickjs
Documentation
// SPDX-License-Identifier: MIT OR Apache-2.0
//! Shared access to ArrayBufferView backing stores.
use super::*;

use rquickjs::{ArrayBuffer, Function, Object};

pub(super) unsafe fn view_ptr(buffer: V, offset: usize, byte_length: usize) -> Status<*mut c_void> {
    let ab = ArrayBuffer::from_value(buffer).ok_or(NAPI_INVALID_ARG)?;
    let raw = ab.as_raw().ok_or(NAPI_INVALID_ARG)?;
    let end = offset.checked_add(byte_length).ok_or(NAPI_INVALID_ARG)?;
    if end > raw.len() {
        return Err(NAPI_INVALID_ARG);
    }
    Ok((raw.as_ptr() as *mut u8).add(offset) as *mut c_void)
}

/// Returns `(byteLength, byteOffset, buffer)` for any ArrayBufferView.
pub(super) unsafe fn buf_info(env: napi_env, value: napi_value) -> Status<(usize, usize, V)> {
    let value = get(value)?;
    if !is_array_buffer_view(env, value)? {
        return Err(NAPI_INVALID_ARG);
    }
    let view = value.as_object().ok_or(NAPI_INVALID_ARG)?;
    let byte_length = js(env, view.get("byteLength"))?;
    let byte_offset = js(env, view.get("byteOffset"))?;
    let buffer = js(env, view.get("buffer"))?;
    Ok((byte_length, byte_offset, buffer))
}

pub(super) unsafe fn is_array_buffer_view(env: napi_env, value: &V) -> Status<bool> {
    let globals = ctx(env).globals();
    let array_buffer: Object = js(env, globals.get("ArrayBuffer"))?;
    let is_view: Function = js(env, array_buffer.get("isView"))?;
    js(env, is_view.call((value.clone(),)))
}

#[allow(clippy::unnecessary_cast)]
pub(super) unsafe fn view_info(
    env: napi_env,
    value: napi_value,
) -> Status<(u32, usize, usize, usize, V)> {
    let value = get(value)?;
    let kind = qjs::JS_GetTypedArrayType(value.as_raw());
    if kind < 0 {
        return Err(NAPI_INVALID_ARG);
    }

    let mut offset = 0;
    let mut byte_length = 0;
    let mut bytes_per_element = 0;
    let raw_buffer = qjs::JS_GetTypedArrayBuffer(
        ctx(env).as_raw().as_ptr(),
        value.as_raw(),
        &mut offset,
        &mut byte_length,
        &mut bytes_per_element,
    );
    if qjs::JS_IsException(raw_buffer) {
        (*env).exception = Some(extend(ctx(env).catch()));
        return Err(NAPI_PENDING_EXCEPTION);
    }
    if bytes_per_element == 0 {
        qjs::JS_FreeValue(ctx(env).as_raw().as_ptr(), raw_buffer);
        return Err(NAPI_GENERIC_FAILURE);
    }
    let buffer = extend(Value::from_raw(ctx(env), raw_buffer));
    const INT8: u32 = qjs::JSTypedArrayEnum_JS_TYPED_ARRAY_INT8 as u32;
    const UINT8: u32 = qjs::JSTypedArrayEnum_JS_TYPED_ARRAY_UINT8 as u32;
    const UINT8C: u32 = qjs::JSTypedArrayEnum_JS_TYPED_ARRAY_UINT8C as u32;
    const INT16: u32 = qjs::JSTypedArrayEnum_JS_TYPED_ARRAY_INT16 as u32;
    const UINT16: u32 = qjs::JSTypedArrayEnum_JS_TYPED_ARRAY_UINT16 as u32;
    const INT32: u32 = qjs::JSTypedArrayEnum_JS_TYPED_ARRAY_INT32 as u32;
    const UINT32: u32 = qjs::JSTypedArrayEnum_JS_TYPED_ARRAY_UINT32 as u32;
    const FLOAT32: u32 = qjs::JSTypedArrayEnum_JS_TYPED_ARRAY_FLOAT32 as u32;
    const FLOAT64: u32 = qjs::JSTypedArrayEnum_JS_TYPED_ARRAY_FLOAT64 as u32;
    const BIG_INT64: u32 = qjs::JSTypedArrayEnum_JS_TYPED_ARRAY_BIG_INT64 as u32;
    const BIG_UINT64: u32 = qjs::JSTypedArrayEnum_JS_TYPED_ARRAY_BIG_UINT64 as u32;
    let napi_kind = match kind as u32 {
        INT8 => 0,
        UINT8 => 1,
        UINT8C => 2,
        INT16 => 3,
        UINT16 => 4,
        INT32 => 5,
        UINT32 => 6,
        FLOAT32 => 7,
        FLOAT64 => 8,
        BIG_INT64 => 9,
        BIG_UINT64 => 10,
        _ => 1,
    };
    Ok((
        napi_kind,
        (byte_length / bytes_per_element) as usize,
        offset as usize,
        byte_length as usize,
        buffer,
    ))
}