refactor(napi): scope and Ref
This commit is contained in:
parent
4460f43be8
commit
9c921ffaa3
36 changed files with 619 additions and 474 deletions
|
@ -1,17 +1,20 @@
|
|||
use napi::{CallContext, Env, JsBuffer, JsNumber, JsObject, Module, Result, Task};
|
||||
use napi::{
|
||||
CallContext, Env, JsBuffer, JsBufferValue, JsNumber, JsObject, Module, Ref, Result, Task,
|
||||
};
|
||||
|
||||
#[repr(transparent)]
|
||||
struct BufferLength(&'static [u8]);
|
||||
struct BufferLength(Ref<JsBufferValue>);
|
||||
|
||||
impl Task for BufferLength {
|
||||
type Output = usize;
|
||||
type JsValue = JsNumber;
|
||||
|
||||
fn compute(&mut self) -> Result<Self::Output> {
|
||||
Ok(self.0.len())
|
||||
Ok((&self.0).len())
|
||||
}
|
||||
|
||||
fn resolve(&self, env: &mut Env, output: Self::Output) -> Result<Self::JsValue> {
|
||||
fn resolve(self, env: Env, output: Self::Output) -> Result<Self::JsValue> {
|
||||
self.0.unref(env)?;
|
||||
env.create_uint32(output as u32)
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +22,7 @@ impl Task for BufferLength {
|
|||
#[js_function(1)]
|
||||
fn bench_async_task(ctx: CallContext) -> Result<JsObject> {
|
||||
let n = ctx.get::<JsBuffer>(0)?;
|
||||
let task = BufferLength(n.data);
|
||||
let task = BufferLength(n.into_ref()?);
|
||||
let async_promise = ctx.env.spawn(task)?;
|
||||
Ok(async_promise.promise_object())
|
||||
}
|
||||
|
|
|
@ -176,13 +176,13 @@ fn get_execute_js_code(
|
|||
let return_token_stream = match function_kind {
|
||||
FunctionKind::Contextless => {
|
||||
quote! {
|
||||
Ok(Some(v)) => v.raw_value(),
|
||||
Ok(Some(v)) => v.raw(),
|
||||
Ok(None) => ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
FunctionKind::JsFunction => {
|
||||
quote! {
|
||||
Ok(v) => v.raw_value(),
|
||||
Ok(v) => v.raw(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -80,6 +80,8 @@ unsafe impl<T: Task> Send for AsyncWork<T> {}
|
|||
|
||||
unsafe impl<T: Task> Sync for AsyncWork<T> {}
|
||||
|
||||
/// env here is the same with the one in `CallContext`.
|
||||
/// So it actually could do nothing here, because `execute` function is called in the other thread mostly.
|
||||
unsafe extern "C" fn execute<T: Task>(_env: sys::napi_env, data: *mut c_void) {
|
||||
let mut work = Box::from_raw(data as *mut AsyncWork<T>);
|
||||
let _ = mem::replace(
|
||||
|
@ -100,11 +102,11 @@ unsafe extern "C" fn complete<T: Task>(
|
|||
let napi_async_work = mem::replace(&mut work.napi_async_work, ptr::null_mut());
|
||||
let value = value_ptr.and_then(move |v| {
|
||||
let output = v.assume_init();
|
||||
work.inner_task.resolve(&mut Env::from_raw(env), output)
|
||||
work.inner_task.resolve(Env::from_raw(env), output)
|
||||
});
|
||||
match check_status(status).and_then(move |_| value) {
|
||||
Ok(v) => {
|
||||
let status = sys::napi_resolve_deferred(env, deferred, v.raw_value());
|
||||
let status = sys::napi_resolve_deferred(env, deferred, v.raw());
|
||||
debug_assert!(status == sys::napi_status::napi_ok, "Reject promise failed");
|
||||
}
|
||||
Err(e) => {
|
||||
|
|
|
@ -30,6 +30,7 @@ use tokio::sync::mpsc::error::TrySendError;
|
|||
|
||||
pub type Callback = extern "C" fn(sys::napi_env, sys::napi_callback_info) -> sys::napi_value;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Env(pub(crate) sys::napi_env);
|
||||
|
||||
|
@ -219,28 +220,26 @@ impl Env {
|
|||
Ok(JsObject::from_raw_unchecked(self.0, raw_value))
|
||||
}
|
||||
|
||||
pub fn create_buffer<'env, 'buffer>(&'env self, length: u64) -> Result<JsBuffer<'buffer>> {
|
||||
pub fn create_buffer(&self, length: u64) -> Result<JsBufferValue> {
|
||||
let mut raw_value = ptr::null_mut();
|
||||
let mut data = Vec::with_capacity(length as usize);
|
||||
let mut data_ptr = data.as_mut_ptr();
|
||||
let mut data: Vec<u8> = Vec::with_capacity(length as usize);
|
||||
let mut data_ptr = data.as_mut_ptr() as *mut c_void;
|
||||
check_status(unsafe {
|
||||
sys::napi_create_buffer(self.0, length, &mut data_ptr, &mut raw_value)
|
||||
})?;
|
||||
mem::forget(data);
|
||||
|
||||
Ok(JsBuffer::new(
|
||||
self.0,
|
||||
raw_value,
|
||||
data_ptr as *mut u8,
|
||||
length as usize,
|
||||
Ok(JsBufferValue::new(
|
||||
JsBuffer(Value {
|
||||
env: self.0,
|
||||
value: raw_value,
|
||||
value_type: ValueType::Object,
|
||||
}),
|
||||
data,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn create_buffer_with_data<'env, 'buffer>(
|
||||
&'env self,
|
||||
mut data: Vec<u8>,
|
||||
) -> Result<JsBuffer<'buffer>> {
|
||||
let length = data.len() as u64;
|
||||
pub fn create_buffer_with_data(&self, mut data: Vec<u8>) -> Result<JsBufferValue> {
|
||||
let mut length = data.len() as u64;
|
||||
let mut raw_value = ptr::null_mut();
|
||||
let data_ptr = data.as_mut_ptr();
|
||||
check_status(unsafe {
|
||||
|
@ -249,14 +248,20 @@ impl Env {
|
|||
length,
|
||||
data_ptr as *mut c_void,
|
||||
Some(drop_buffer),
|
||||
Box::leak(Box::new(length)) as *mut u64 as *mut _,
|
||||
&mut length as *mut u64 as *mut _,
|
||||
&mut raw_value,
|
||||
)
|
||||
})?;
|
||||
let mut changed = 0;
|
||||
check_status(unsafe { sys::napi_adjust_external_memory(self.0, length as i64, &mut changed) })?;
|
||||
mem::forget(data);
|
||||
Ok(JsBuffer::new(self.0, raw_value, data_ptr, length as usize))
|
||||
Ok(JsBufferValue::new(
|
||||
JsBuffer(Value {
|
||||
env: self.0,
|
||||
value: raw_value,
|
||||
value_type: ValueType::Object,
|
||||
}),
|
||||
data,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn create_arraybuffer(&self, length: u64) -> Result<JsArrayBuffer> {
|
||||
|
@ -328,25 +333,6 @@ impl Env {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn create_reference<T: NapiValue>(&self, value: T) -> Result<Ref<T>> {
|
||||
let mut raw_ref = ptr::null_mut();
|
||||
let initial_ref_count = 1;
|
||||
check_status(unsafe {
|
||||
sys::napi_create_reference(self.0, value.raw_value(), initial_ref_count, &mut raw_ref)
|
||||
})?;
|
||||
|
||||
Ok(Ref::new(self.0, raw_ref))
|
||||
}
|
||||
|
||||
pub fn get_reference_value<T: NapiValue>(&self, reference: &Ref<T>) -> Result<T> {
|
||||
let mut raw_value = ptr::null_mut();
|
||||
check_status(unsafe {
|
||||
sys::napi_get_reference_value(self.0, reference.ref_value, &mut raw_value)
|
||||
})?;
|
||||
|
||||
T::from_raw(self.0, raw_value)
|
||||
}
|
||||
|
||||
pub fn define_class(
|
||||
&self,
|
||||
name: &str,
|
||||
|
@ -491,6 +477,19 @@ impl Env {
|
|||
async_work::run(self, task)
|
||||
}
|
||||
|
||||
pub fn run_in_scope<T, F>(&self, executor: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce() -> Result<T>,
|
||||
{
|
||||
let mut handle_scope = ptr::null_mut();
|
||||
check_status(unsafe { sys::napi_open_handle_scope(self.0, &mut handle_scope) })?;
|
||||
|
||||
let result = executor();
|
||||
|
||||
check_status(unsafe { sys::napi_close_handle_scope(self.0, handle_scope) })?;
|
||||
result
|
||||
}
|
||||
|
||||
pub fn get_global(&self) -> Result<JsObject> {
|
||||
let mut raw_global = ptr::null_mut();
|
||||
check_status(unsafe { sys::napi_get_global(self.0, &mut raw_global) })?;
|
||||
|
@ -503,6 +502,7 @@ impl Env {
|
|||
let versions: JsObject = process.get_named_property("versions")?;
|
||||
let napi_version: JsString = versions.get_named_property("napi")?;
|
||||
napi_version
|
||||
.into_utf8()?
|
||||
.as_str()?
|
||||
.parse()
|
||||
.map_err(|e| Error::new(Status::InvalidArg, format!("{}", e)))
|
||||
|
@ -622,7 +622,7 @@ impl Env {
|
|||
{
|
||||
let value = Value {
|
||||
env: self.0,
|
||||
value: value.raw_value(),
|
||||
value: value.raw(),
|
||||
value_type: ValueType::Unknown,
|
||||
};
|
||||
let mut de = De(&value);
|
||||
|
@ -631,9 +631,7 @@ impl Env {
|
|||
|
||||
pub fn strict_equals<A: NapiValue, B: NapiValue>(&self, a: A, b: B) -> Result<bool> {
|
||||
let mut result = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_strict_equals(self.0, a.raw_value(), b.raw_value(), &mut result)
|
||||
})?;
|
||||
check_status(unsafe { sys::napi_strict_equals(self.0, a.raw(), b.raw(), &mut result) })?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
|
@ -646,7 +644,7 @@ impl Env {
|
|||
}
|
||||
|
||||
unsafe extern "C" fn drop_buffer(env: sys::napi_env, finalize_data: *mut c_void, len: *mut c_void) {
|
||||
let length = Box::from_raw(len as *mut u64);
|
||||
let length = len as *mut u64;
|
||||
let length = *length as usize;
|
||||
let _ = Vec::from_raw_parts(finalize_data as *mut u8, length, length);
|
||||
let mut changed = 0;
|
||||
|
|
|
@ -126,7 +126,7 @@ impl JsArrayBuffer {
|
|||
sys::napi_instanceof(
|
||||
self.value.0.env,
|
||||
self.value.0.value,
|
||||
constructor.raw_value(),
|
||||
constructor.raw(),
|
||||
&mut result,
|
||||
)
|
||||
})?;
|
||||
|
@ -135,7 +135,7 @@ impl JsArrayBuffer {
|
|||
}
|
||||
|
||||
impl NapiValue for JsArrayBuffer {
|
||||
fn raw_value(&self) -> sys::napi_value {
|
||||
fn raw(&self) -> sys::napi_value {
|
||||
self.value.0.value
|
||||
}
|
||||
|
||||
|
|
|
@ -117,19 +117,14 @@ impl JsBigint {
|
|||
pub fn instanceof<Constructor: NapiValue>(&self, constructor: Constructor) -> Result<bool> {
|
||||
let mut result = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_instanceof(
|
||||
self.raw.env,
|
||||
self.raw.value,
|
||||
constructor.raw_value(),
|
||||
&mut result,
|
||||
)
|
||||
sys::napi_instanceof(self.raw.env, self.raw.value, constructor.raw(), &mut result)
|
||||
})?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl NapiValue for JsBigint {
|
||||
fn raw_value(&self) -> sys::napi_value {
|
||||
fn raw(&self) -> sys::napi_value {
|
||||
self.raw.value
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ use super::Value;
|
|||
use crate::error::check_status;
|
||||
use crate::{sys, Error, Result};
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct JsBoolean(pub(crate) Value);
|
||||
|
||||
|
|
|
@ -1,194 +1,88 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
|
||||
use super::{JsNumber, JsObject, JsString, JsUnknown, NapiValue, Status, Value, ValueType};
|
||||
use super::Value;
|
||||
#[cfg(feature = "serde-json")]
|
||||
use super::ValueType;
|
||||
use crate::error::check_status;
|
||||
use crate::{sys, Error, Result};
|
||||
use crate::{sys, JsUnknown, Ref, Result};
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct JsBuffer(pub(crate) Value);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JsBuffer<'buffer> {
|
||||
pub value: JsObject,
|
||||
pub data: &'buffer [u8],
|
||||
pub struct JsBufferValue {
|
||||
pub(crate) value: JsBuffer,
|
||||
data: mem::ManuallyDrop<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl<'buffer> JsBuffer<'buffer> {
|
||||
pub(crate) fn new(env: sys::napi_env, value: sys::napi_value, data: *mut u8, len: usize) -> Self {
|
||||
Self {
|
||||
value: JsObject(Value {
|
||||
env,
|
||||
value,
|
||||
value_type: ValueType::Object,
|
||||
}),
|
||||
data: unsafe { slice::from_raw_parts_mut(data, len) },
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_unknown(self) -> Result<JsUnknown> {
|
||||
JsUnknown::from_raw(self.value.0.env, self.value.0.value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn coerce_to_number(self) -> Result<JsNumber> {
|
||||
let mut new_raw_value = ptr::null_mut();
|
||||
check_status(unsafe {
|
||||
sys::napi_coerce_to_number(self.value.0.env, self.value.0.value, &mut new_raw_value)
|
||||
})?;
|
||||
Ok(JsNumber(Value {
|
||||
env: self.value.0.env,
|
||||
value: new_raw_value,
|
||||
value_type: ValueType::Number,
|
||||
}))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn coerce_to_string(self) -> Result<JsString> {
|
||||
let mut new_raw_value = ptr::null_mut();
|
||||
check_status(unsafe {
|
||||
sys::napi_coerce_to_string(self.value.0.env, self.value.0.value, &mut new_raw_value)
|
||||
})?;
|
||||
Ok(JsString(Value {
|
||||
env: self.value.0.env,
|
||||
value: new_raw_value,
|
||||
value_type: ValueType::String,
|
||||
}))
|
||||
}
|
||||
#[inline]
|
||||
pub fn coerce_to_object(self) -> Result<JsObject> {
|
||||
let mut new_raw_value = ptr::null_mut();
|
||||
check_status(unsafe {
|
||||
sys::napi_coerce_to_object(self.value.0.env, self.value.0.value, &mut new_raw_value)
|
||||
})?;
|
||||
Ok(JsObject(Value {
|
||||
env: self.value.0.env,
|
||||
value: new_raw_value,
|
||||
value_type: ValueType::Object,
|
||||
}))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(napi5)]
|
||||
pub fn is_date(&self) -> Result<bool> {
|
||||
let mut is_date = true;
|
||||
check_status(unsafe { sys::napi_is_date(self.value.0.env, self.value.0.value, &mut is_date) })?;
|
||||
Ok(is_date)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_error(&self) -> Result<bool> {
|
||||
let mut result = false;
|
||||
check_status(unsafe { sys::napi_is_error(self.value.0.env, self.value.0.value, &mut result) })?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_typedarray(&self) -> Result<bool> {
|
||||
let mut result = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_is_typedarray(self.value.0.env, self.value.0.value, &mut result)
|
||||
})?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_dataview(&self) -> Result<bool> {
|
||||
let mut result = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_is_dataview(self.value.0.env, self.value.0.value, &mut result)
|
||||
})?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_array(&self) -> Result<bool> {
|
||||
let mut is_array = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_is_array(self.value.0.env, self.value.0.value, &mut is_array)
|
||||
})?;
|
||||
Ok(is_array)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_buffer(&self) -> Result<bool> {
|
||||
let mut is_buffer = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_is_buffer(self.value.0.env, self.value.0.value, &mut is_buffer)
|
||||
})?;
|
||||
Ok(is_buffer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn instanceof<Constructor: NapiValue>(&self, constructor: Constructor) -> Result<bool> {
|
||||
let mut result = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_instanceof(
|
||||
self.value.0.env,
|
||||
self.value.0.value,
|
||||
constructor.raw_value(),
|
||||
&mut result,
|
||||
)
|
||||
})?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'buffer> NapiValue for JsBuffer<'buffer> {
|
||||
fn raw_value(&self) -> sys::napi_value {
|
||||
self.value.0.value
|
||||
}
|
||||
|
||||
fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
|
||||
impl JsBuffer {
|
||||
pub fn into_value(self) -> Result<JsBufferValue> {
|
||||
let mut data = ptr::null_mut();
|
||||
let mut len: u64 = 0;
|
||||
check_status(unsafe { sys::napi_get_buffer_info(env, value, &mut data, &mut len) })?;
|
||||
Ok(JsBuffer {
|
||||
value: JsObject(Value {
|
||||
env,
|
||||
value,
|
||||
value_type: ValueType::Object,
|
||||
check_status(unsafe {
|
||||
sys::napi_get_buffer_info(self.0.env, self.0.value, &mut data, &mut len)
|
||||
})?;
|
||||
Ok(JsBufferValue {
|
||||
data: mem::ManuallyDrop::new(unsafe {
|
||||
Vec::from_raw_parts(data as *mut _, len as usize, len as usize)
|
||||
}),
|
||||
data: unsafe { slice::from_raw_parts_mut(data as *mut _, len as usize) },
|
||||
value: self,
|
||||
})
|
||||
}
|
||||
|
||||
fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> Self {
|
||||
#[inline]
|
||||
pub fn into_ref(self) -> Result<Ref<JsBufferValue>> {
|
||||
Ref::new(self.0, 1, self.into_value()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl JsBufferValue {
|
||||
#[cfg(feature = "serde-json")]
|
||||
pub(crate) fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
|
||||
let mut data = ptr::null_mut();
|
||||
let mut len: u64 = 0;
|
||||
let status = unsafe { sys::napi_get_buffer_info(env, value, &mut data, &mut len) };
|
||||
debug_assert!(
|
||||
Status::from(status) == Status::Ok,
|
||||
"napi_get_buffer_info failed"
|
||||
);
|
||||
JsBuffer {
|
||||
value: JsObject(Value {
|
||||
check_status(unsafe { sys::napi_get_buffer_info(env, value, &mut data, &mut len) })?;
|
||||
Ok(Self {
|
||||
value: JsBuffer(Value {
|
||||
env,
|
||||
value,
|
||||
value_type: ValueType::Object,
|
||||
}),
|
||||
data: unsafe { slice::from_raw_parts_mut(data as *mut _, len as usize) },
|
||||
data: mem::ManuallyDrop::new(unsafe {
|
||||
Vec::from_raw_parts(data as *mut _, len as usize, len as usize)
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new(value: JsBuffer, data: Vec<u8>) -> Self {
|
||||
JsBufferValue {
|
||||
value,
|
||||
data: mem::ManuallyDrop::new(data),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'buffer> AsRef<[u8]> for JsBuffer<'buffer> {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.data
|
||||
pub fn into_raw(self) -> JsBuffer {
|
||||
self.value
|
||||
}
|
||||
|
||||
pub fn into_unknown(self) -> Result<JsUnknown> {
|
||||
self.value.into_unknown()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'buffer> Deref for JsBuffer<'buffer> {
|
||||
impl AsRef<[u8]> for JsBufferValue {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.data.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for JsBufferValue {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<'buffer> TryFrom<JsUnknown> for JsBuffer<'buffer> {
|
||||
type Error = Error;
|
||||
fn try_from(value: JsUnknown) -> Result<JsBuffer<'buffer>> {
|
||||
JsBuffer::from_raw(value.0.env, value.0.value)
|
||||
self.data.as_slice()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,9 @@ use serde::de::{DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Unexpected, V
|
|||
use super::{type_of, NapiValue, Value, ValueType};
|
||||
#[cfg(napi6)]
|
||||
use crate::JsBigint;
|
||||
use crate::{Error, JsBoolean, JsBuffer, JsNumber, JsObject, JsString, JsUnknown, Result, Status};
|
||||
use crate::{
|
||||
Error, JsBoolean, JsBufferValue, JsNumber, JsObject, JsString, JsUnknown, Result, Status,
|
||||
};
|
||||
|
||||
pub(crate) struct De<'env>(pub(crate) &'env Value);
|
||||
|
||||
|
@ -35,7 +37,7 @@ impl<'x, 'de, 'env> serde::de::Deserializer<'x> for &'de mut De<'env> {
|
|||
}
|
||||
ValueType::String => {
|
||||
let js_string = JsString::from_raw_unchecked(self.0.env, self.0.value);
|
||||
visitor.visit_str(js_string.as_str()?)
|
||||
visitor.visit_str(js_string.into_utf8()?.as_str()?)
|
||||
}
|
||||
ValueType::Object => {
|
||||
let js_object = JsObject::from_raw_unchecked(self.0.env, self.0.value);
|
||||
|
@ -44,7 +46,7 @@ impl<'x, 'de, 'env> serde::de::Deserializer<'x> for &'de mut De<'env> {
|
|||
JsArrayAccess::new(&js_object, js_object.get_array_length_unchecked()?);
|
||||
visitor.visit_seq(&mut deserializer)
|
||||
} else if js_object.is_buffer()? {
|
||||
visitor.visit_bytes(JsBuffer::from_raw(self.0.env, self.0.value)?.data)
|
||||
visitor.visit_bytes(&JsBufferValue::from_raw(self.0.env, self.0.value)?)
|
||||
} else {
|
||||
let mut deserializer = JsObjectAccess::new(&js_object)?;
|
||||
visitor.visit_map(&mut deserializer)
|
||||
|
@ -72,14 +74,14 @@ impl<'x, 'de, 'env> serde::de::Deserializer<'x> for &'de mut De<'env> {
|
|||
where
|
||||
V: Visitor<'x>,
|
||||
{
|
||||
visitor.visit_bytes(JsBuffer::from_raw(self.0.env, self.0.value)?.data)
|
||||
visitor.visit_bytes(&JsBufferValue::from_raw(self.0.env, self.0.value)?)
|
||||
}
|
||||
|
||||
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
|
||||
where
|
||||
V: Visitor<'x>,
|
||||
{
|
||||
visitor.visit_bytes(JsBuffer::from_raw(self.0.env, self.0.value)?.data)
|
||||
visitor.visit_bytes(&JsBufferValue::from_raw(self.0.env, self.0.value)?)
|
||||
}
|
||||
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
|
||||
|
@ -105,8 +107,8 @@ impl<'x, 'de, 'env> serde::de::Deserializer<'x> for &'de mut De<'env> {
|
|||
match js_value_type {
|
||||
ValueType::String => visitor.visit_enum(JsEnumAccess::new(
|
||||
JsString::from_raw_unchecked(self.0.env, self.0.value)
|
||||
.as_str()?
|
||||
.to_owned(),
|
||||
.into_utf8()?
|
||||
.to_owned()?,
|
||||
None,
|
||||
)),
|
||||
ValueType::Object => {
|
||||
|
@ -124,7 +126,10 @@ impl<'x, 'de, 'env> serde::de::Deserializer<'x> for &'de mut De<'env> {
|
|||
} else {
|
||||
let key = properties.get_element::<JsString>(0)?;
|
||||
let value: JsUnknown = js_object.get_property(&key)?;
|
||||
visitor.visit_enum(JsEnumAccess::new(key.as_str()?.to_owned(), Some(&value.0)))
|
||||
visitor.visit_enum(JsEnumAccess::new(
|
||||
key.into_utf8()?.to_owned()?,
|
||||
Some(&value.0),
|
||||
))
|
||||
}
|
||||
}
|
||||
_ => Err(Error::new(
|
||||
|
|
|
@ -26,10 +26,10 @@ impl<A: NapiValue, B: NapiValue> NapiValue for Either<A, B> {
|
|||
Self::from_raw(env, value).unwrap()
|
||||
}
|
||||
|
||||
fn raw_value(&self) -> sys::napi_value {
|
||||
fn raw(&self) -> sys::napi_value {
|
||||
match self {
|
||||
Either::A(v) => v.raw_value(),
|
||||
Either::B(v) => v.raw_value(),
|
||||
Either::A(v) => v.raw(),
|
||||
Either::B(v) => v.raw(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
39
napi/src/js_values/escapable_handle_scope.rs
Normal file
39
napi/src/js_values/escapable_handle_scope.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
|
||||
use super::check_status;
|
||||
use crate::{sys, Env, NapiValue, Result};
|
||||
|
||||
pub struct EscapableHandleScope<T: NapiValue> {
|
||||
handle_scope: sys::napi_escapable_handle_scope,
|
||||
value: T,
|
||||
}
|
||||
|
||||
impl<T: NapiValue> EscapableHandleScope<T> {
|
||||
#[inline]
|
||||
pub fn open(env: sys::napi_env, value: T) -> Result<Self> {
|
||||
let mut handle_scope = ptr::null_mut();
|
||||
check_status(unsafe { sys::napi_open_escapable_handle_scope(env, &mut handle_scope) })?;
|
||||
let mut result = ptr::null_mut();
|
||||
check_status(unsafe {
|
||||
sys::napi_escape_handle(env, handle_scope, NapiValue::raw(&value), &mut result)
|
||||
})?;
|
||||
Ok(Self {
|
||||
value,
|
||||
handle_scope,
|
||||
})
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn close(self, env: Env) -> Result<()> {
|
||||
check_status(unsafe { sys::napi_close_escapable_handle_scope(env.0, self.handle_scope) })
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: NapiValue> Deref for EscapableHandleScope<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.value
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ use super::Value;
|
|||
use crate::error::check_status;
|
||||
use crate::{sys, Env, Error, JsObject, JsUnknown, NapiValue, Result, Status};
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct JsFunction(pub(crate) Value);
|
||||
|
||||
|
@ -26,12 +27,12 @@ impl JsFunction {
|
|||
/// [napi_call_function](https://nodejs.org/api/n-api.html#n_api_napi_call_function)
|
||||
pub fn call(&self, this: Option<&JsObject>, args: &[JsUnknown]) -> Result<JsUnknown> {
|
||||
let raw_this = this
|
||||
.map(|v| v.raw_value())
|
||||
.map(|v| v.raw())
|
||||
.or_else(|| {
|
||||
Env::from_raw(self.0.env)
|
||||
.get_undefined()
|
||||
.ok()
|
||||
.map(|u| u.raw_value())
|
||||
.map(|u| u.raw())
|
||||
})
|
||||
.ok_or(Error::new(
|
||||
Status::Unknown,
|
||||
|
|
|
@ -15,6 +15,7 @@ mod bigint;
|
|||
mod boolean;
|
||||
mod buffer;
|
||||
mod either;
|
||||
mod escapable_handle_scope;
|
||||
mod function;
|
||||
mod number;
|
||||
mod object;
|
||||
|
@ -30,33 +31,38 @@ pub use arraybuffer::JsArrayBuffer;
|
|||
#[cfg(napi6)]
|
||||
pub use bigint::JsBigint;
|
||||
pub use boolean::JsBoolean;
|
||||
pub use buffer::JsBuffer;
|
||||
pub use buffer::*;
|
||||
#[cfg(feature = "serde-json")]
|
||||
pub(crate) use de::De;
|
||||
pub use either::Either;
|
||||
pub use escapable_handle_scope::EscapableHandleScope;
|
||||
pub use function::JsFunction;
|
||||
pub use number::JsNumber;
|
||||
pub use object::JsObject;
|
||||
pub use object_property::Property;
|
||||
#[cfg(feature = "serde-json")]
|
||||
pub(crate) use ser::Ser;
|
||||
pub use string::JsString;
|
||||
pub use string::*;
|
||||
pub(crate) use tagged_object::TaggedObject;
|
||||
pub use undefined::JsUndefined;
|
||||
pub(crate) use value::Value;
|
||||
pub(crate) use value_ref::Ref;
|
||||
pub use value_ref::Ref;
|
||||
pub use value_type::ValueType;
|
||||
|
||||
// Value types
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct JsUnknown(pub(crate) Value);
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct JsNull(pub(crate) Value);
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct JsSymbol(pub(crate) Value);
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct JsExternal(pub(crate) Value);
|
||||
|
||||
|
@ -88,7 +94,7 @@ macro_rules! impl_napi_value_trait {
|
|||
}
|
||||
}
|
||||
|
||||
fn raw_value(&self) -> sys::napi_value {
|
||||
fn raw(&self) -> sys::napi_value {
|
||||
self.0.value
|
||||
}
|
||||
|
||||
|
@ -130,6 +136,7 @@ macro_rules! impl_js_value_methods {
|
|||
value_type: ValueType::Number,
|
||||
}))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn coerce_to_string(self) -> Result<JsString> {
|
||||
let mut new_raw_value = ptr::null_mut();
|
||||
|
@ -204,12 +211,7 @@ macro_rules! impl_js_value_methods {
|
|||
pub fn instanceof<Constructor: NapiValue>(&self, constructor: Constructor) -> Result<bool> {
|
||||
let mut result = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_instanceof(
|
||||
self.0.env,
|
||||
self.0.value,
|
||||
constructor.raw_value(),
|
||||
&mut result,
|
||||
)
|
||||
sys::napi_instanceof(self.0.env, self.0.value, constructor.raw(), &mut result)
|
||||
})?;
|
||||
Ok(result)
|
||||
}
|
||||
|
@ -222,13 +224,14 @@ pub trait NapiValue: Sized {
|
|||
|
||||
fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> Self;
|
||||
|
||||
fn raw_value(&self) -> sys::napi_value;
|
||||
fn raw(&self) -> sys::napi_value;
|
||||
}
|
||||
|
||||
impl_js_value_methods!(JsUnknown);
|
||||
impl_js_value_methods!(JsUndefined);
|
||||
impl_js_value_methods!(JsNull);
|
||||
impl_js_value_methods!(JsBoolean);
|
||||
impl_js_value_methods!(JsBuffer);
|
||||
impl_js_value_methods!(JsNumber);
|
||||
impl_js_value_methods!(JsString);
|
||||
impl_js_value_methods!(JsObject);
|
||||
|
@ -241,6 +244,7 @@ use ValueType::*;
|
|||
impl_napi_value_trait!(JsUndefined, Undefined);
|
||||
impl_napi_value_trait!(JsNull, Null);
|
||||
impl_napi_value_trait!(JsBoolean, Boolean);
|
||||
impl_napi_value_trait!(JsBuffer, Object);
|
||||
impl_napi_value_trait!(JsNumber, Number);
|
||||
impl_napi_value_trait!(JsString, String);
|
||||
impl_napi_value_trait!(JsObject, Object);
|
||||
|
@ -265,7 +269,7 @@ impl NapiValue for JsUnknown {
|
|||
})
|
||||
}
|
||||
|
||||
fn raw_value(&self) -> sys::napi_value {
|
||||
fn raw(&self) -> sys::napi_value {
|
||||
self.0.value
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ use super::Value;
|
|||
use crate::error::check_status;
|
||||
use crate::{sys, Error, Result};
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct JsNumber(pub(crate) Value);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ use super::Value;
|
|||
use crate::error::check_status;
|
||||
use crate::{sys, Error, JsString, NapiValue, Property, Result, Status};
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct JsObject(pub(crate) Value);
|
||||
|
||||
|
@ -14,7 +15,7 @@ impl JsObject {
|
|||
V: NapiValue,
|
||||
{
|
||||
check_status(unsafe {
|
||||
sys::napi_set_property(self.0.env, self.0.value, key.0.value, value.raw_value())
|
||||
sys::napi_set_property(self.0.env, self.0.value, key.0.value, value.raw())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -25,7 +26,7 @@ impl JsObject {
|
|||
{
|
||||
let mut raw_value = ptr::null_mut();
|
||||
check_status(unsafe {
|
||||
sys::napi_get_property(self.0.env, self.0.value, key.raw_value(), &mut raw_value)
|
||||
sys::napi_get_property(self.0.env, self.0.value, key.raw(), &mut raw_value)
|
||||
})?;
|
||||
T::from_raw(self.0.env, raw_value)
|
||||
}
|
||||
|
@ -36,7 +37,7 @@ impl JsObject {
|
|||
{
|
||||
let key = CString::new(name)?;
|
||||
check_status(unsafe {
|
||||
sys::napi_set_named_property(self.0.env, self.0.value, key.as_ptr(), value.raw_value())
|
||||
sys::napi_set_named_property(self.0.env, self.0.value, key.as_ptr(), value.raw())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -70,7 +71,7 @@ impl JsObject {
|
|||
{
|
||||
let mut result = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_delete_property(self.0.env, self.0.value, name.raw_value(), &mut result)
|
||||
sys::napi_delete_property(self.0.env, self.0.value, name.raw(), &mut result)
|
||||
})?;
|
||||
Ok(result)
|
||||
}
|
||||
|
@ -107,7 +108,7 @@ impl JsObject {
|
|||
{
|
||||
let mut result = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_has_own_property(self.0.env, self.0.value, key.raw_value(), &mut result)
|
||||
sys::napi_has_own_property(self.0.env, self.0.value, key.raw(), &mut result)
|
||||
})?;
|
||||
Ok(result)
|
||||
}
|
||||
|
@ -129,7 +130,7 @@ impl JsObject {
|
|||
{
|
||||
let mut result = false;
|
||||
check_status(unsafe {
|
||||
sys::napi_has_property(self.0.env, self.0.value, name.raw_value(), &mut result)
|
||||
sys::napi_has_property(self.0.env, self.0.value, name.raw(), &mut result)
|
||||
})?;
|
||||
Ok(result)
|
||||
}
|
||||
|
@ -157,9 +158,7 @@ impl JsObject {
|
|||
where
|
||||
T: NapiValue,
|
||||
{
|
||||
check_status(unsafe {
|
||||
sys::napi_set_element(self.0.env, self.0.value, index, value.raw_value())
|
||||
})
|
||||
check_status(unsafe { sys::napi_set_element(self.0.env, self.0.value, index, value.raw()) })
|
||||
}
|
||||
|
||||
pub fn has_element(&self, index: u32) -> Result<bool> {
|
||||
|
@ -215,7 +214,7 @@ impl JsObject {
|
|||
#[inline]
|
||||
pub fn get_array_length_unchecked(&self) -> Result<u32> {
|
||||
let mut length: u32 = 0;
|
||||
check_status(unsafe { sys::napi_get_array_length(self.0.env, self.raw_value(), &mut length) })?;
|
||||
check_status(unsafe { sys::napi_get_array_length(self.0.env, self.raw(), &mut length) })?;
|
||||
Ok(length)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ impl<'env> Property<'env> {
|
|||
}
|
||||
|
||||
pub fn with_value<T: NapiValue>(mut self, value: T) -> Self {
|
||||
self.raw_descriptor.value = T::raw_value(&value);
|
||||
self.raw_descriptor.value = T::raw(&value);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
use std::str;
|
||||
|
||||
#[cfg(feature = "latin1")]
|
||||
use encoding_rs;
|
||||
|
||||
use super::Value;
|
||||
use crate::error::check_status;
|
||||
use crate::{sys, Error, Result, Status};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JsString(pub(crate) Value);
|
||||
|
||||
impl JsString {
|
||||
pub fn utf8_len(&self) -> Result<usize> {
|
||||
let mut length = 0;
|
||||
check_status(unsafe {
|
||||
sys::napi_get_value_string_utf8(self.0.env, self.0.value, ptr::null_mut(), 0, &mut length)
|
||||
})?;
|
||||
Ok(length as usize)
|
||||
}
|
||||
|
||||
pub fn latin1_len(&self) -> Result<usize> {
|
||||
let mut length = 0;
|
||||
check_status(unsafe {
|
||||
sys::napi_get_value_string_latin1(self.0.env, self.0.value, ptr::null_mut(), 0, &mut length)
|
||||
})?;
|
||||
Ok(length as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl JsString {
|
||||
pub fn get_utf8(&self) -> Result<&[u8]> {
|
||||
let mut written_char_count: u64 = 0;
|
||||
let len = self.utf8_len()? + 1;
|
||||
let mut result = Vec::with_capacity(len);
|
||||
unsafe {
|
||||
check_status(sys::napi_get_value_string_utf8(
|
||||
self.0.env,
|
||||
self.0.value,
|
||||
result.as_mut_ptr(),
|
||||
len as u64,
|
||||
&mut written_char_count,
|
||||
))?;
|
||||
let ptr = result.as_ptr();
|
||||
mem::forget(result);
|
||||
Ok(slice::from_raw_parts(
|
||||
ptr as *const u8,
|
||||
written_char_count as usize,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_latin1(&self) -> Result<(&[u8], usize)> {
|
||||
let mut written_char_count: u64 = 0;
|
||||
let len = self.latin1_len()? + 1;
|
||||
let mut result = Vec::with_capacity(len);
|
||||
unsafe {
|
||||
check_status(sys::napi_get_value_string_latin1(
|
||||
self.0.env,
|
||||
self.0.value,
|
||||
result.as_mut_ptr(),
|
||||
len as u64,
|
||||
&mut written_char_count,
|
||||
))?;
|
||||
let ptr = result.as_ptr();
|
||||
mem::forget(result);
|
||||
Ok((
|
||||
slice::from_raw_parts(ptr as *const u8, written_char_count as usize),
|
||||
written_char_count as usize,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_utf8_chars(&self) -> Result<&[char]> {
|
||||
let mut written_char_count: u64 = 0;
|
||||
let len = self.utf8_len()? + 1;
|
||||
let mut result = Vec::with_capacity(len);
|
||||
unsafe {
|
||||
check_status(sys::napi_get_value_string_utf8(
|
||||
self.0.env,
|
||||
self.0.value,
|
||||
result.as_mut_ptr(),
|
||||
len as u64,
|
||||
&mut written_char_count,
|
||||
))?;
|
||||
|
||||
let ptr = result.as_ptr();
|
||||
mem::forget(result);
|
||||
Ok(slice::from_raw_parts(
|
||||
ptr as *const char,
|
||||
written_char_count as usize,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> Result<&str> {
|
||||
str::from_utf8(self.get_utf8()?)
|
||||
.map_err(|e| Error::new(Status::GenericFailure, format!("{:?}", e)))
|
||||
}
|
||||
|
||||
#[cfg(feature = "latin1")]
|
||||
pub fn as_latin1_string(&self) -> Result<String> {
|
||||
let (latin1_bytes, len) = self.get_latin1()?;
|
||||
let mut dst_str = unsafe { String::from_utf8_unchecked(vec![0; len * 2 + 1]) };
|
||||
encoding_rs::mem::convert_latin1_to_str(latin1_bytes, dst_str.as_mut_str());
|
||||
Ok(dst_str)
|
||||
}
|
||||
|
||||
pub fn get_ref_mut(&mut self) -> Result<&mut [u8]> {
|
||||
let mut written_char_count: u64 = 0;
|
||||
let len = self.utf8_len()? + 1;
|
||||
let mut result = Vec::with_capacity(len);
|
||||
unsafe {
|
||||
check_status(sys::napi_get_value_string_utf8(
|
||||
self.0.env,
|
||||
self.0.value,
|
||||
result.as_mut_ptr(),
|
||||
len as u64,
|
||||
&mut written_char_count,
|
||||
))?;
|
||||
|
||||
let ptr = result.as_ptr();
|
||||
mem::forget(result);
|
||||
Ok(slice::from_raw_parts_mut(
|
||||
ptr as *mut _,
|
||||
written_char_count as usize,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<JsString> for Vec<u16> {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: JsString) -> Result<Vec<u16>> {
|
||||
let mut result = Vec::with_capacity(value.utf8_len()? + 1); // Leave room for trailing null byte
|
||||
|
||||
unsafe {
|
||||
let mut written_char_count = 0;
|
||||
check_status(sys::napi_get_value_string_utf16(
|
||||
value.0.env,
|
||||
value.0.value,
|
||||
result.as_mut_ptr(),
|
||||
result.capacity() as u64,
|
||||
&mut written_char_count,
|
||||
))?;
|
||||
result.set_len(written_char_count as usize);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<JsString> for String {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: JsString) -> Result<String> {
|
||||
Ok(value.as_str()?.to_owned())
|
||||
}
|
||||
}
|
45
napi/src/js_values/string/latin1.rs
Normal file
45
napi/src/js_values/string/latin1.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use std::mem::ManuallyDrop;
|
||||
|
||||
#[cfg(feature = "latin1")]
|
||||
use encoding_rs;
|
||||
|
||||
use crate::JsString;
|
||||
|
||||
#[cfg(feature = "latin1")]
|
||||
use crate::Result;
|
||||
|
||||
pub struct JsStringLatin1 {
|
||||
pub(crate) inner: JsString,
|
||||
pub(crate) buf: ManuallyDrop<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl JsStringLatin1 {
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
&self.buf
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.buf.len()
|
||||
}
|
||||
|
||||
pub fn take(self) -> Vec<u8> {
|
||||
self.as_slice().to_vec()
|
||||
}
|
||||
|
||||
pub fn into_value(self) -> JsString {
|
||||
self.inner
|
||||
}
|
||||
|
||||
#[cfg(feature = "latin1")]
|
||||
pub fn into_latin1_string(self) -> Result<String> {
|
||||
let mut dst_str = unsafe { String::from_utf8_unchecked(vec![0; self.len() * 2 + 1]) };
|
||||
encoding_rs::mem::convert_latin1_to_str(self.buf.as_slice(), dst_str.as_mut_str());
|
||||
Ok(dst_str)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JsStringLatin1> for Vec<u8> {
|
||||
fn from(value: JsStringLatin1) -> Self {
|
||||
value.take()
|
||||
}
|
||||
}
|
138
napi/src/js_values/string/mod.rs
Normal file
138
napi/src/js_values/string/mod.rs
Normal file
|
@ -0,0 +1,138 @@
|
|||
use std::mem;
|
||||
use std::ptr;
|
||||
|
||||
use super::Value;
|
||||
use crate::error::check_status;
|
||||
use crate::{sys, Ref, Result};
|
||||
|
||||
pub use latin1::JsStringLatin1;
|
||||
pub use utf16::JsStringUtf16;
|
||||
pub use utf8::JsStringUtf8;
|
||||
|
||||
mod latin1;
|
||||
mod utf16;
|
||||
mod utf8;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct JsString(pub(crate) Value);
|
||||
|
||||
impl JsString {
|
||||
pub fn utf8_len(&self) -> Result<usize> {
|
||||
let mut length = 0;
|
||||
check_status(unsafe {
|
||||
sys::napi_get_value_string_utf8(self.0.env, self.0.value, ptr::null_mut(), 0, &mut length)
|
||||
})?;
|
||||
Ok(length as usize)
|
||||
}
|
||||
|
||||
pub fn utf16_len(&self) -> Result<usize> {
|
||||
let mut length = 0;
|
||||
check_status(unsafe {
|
||||
sys::napi_get_value_string_utf16(self.0.env, self.0.value, ptr::null_mut(), 0, &mut length)
|
||||
})?;
|
||||
Ok(length as usize)
|
||||
}
|
||||
|
||||
pub fn latin1_len(&self) -> Result<usize> {
|
||||
let mut length = 0;
|
||||
check_status(unsafe {
|
||||
sys::napi_get_value_string_latin1(self.0.env, self.0.value, ptr::null_mut(), 0, &mut length)
|
||||
})?;
|
||||
Ok(length as usize)
|
||||
}
|
||||
|
||||
pub fn into_utf8(self) -> Result<JsStringUtf8> {
|
||||
let mut written_char_count: u64 = 0;
|
||||
let len = self.utf8_len()? + 1;
|
||||
let mut result = Vec::with_capacity(len);
|
||||
let buf_ptr = result.as_mut_ptr();
|
||||
check_status(unsafe {
|
||||
sys::napi_get_value_string_utf8(
|
||||
self.0.env,
|
||||
self.0.value,
|
||||
buf_ptr,
|
||||
len as u64,
|
||||
&mut written_char_count,
|
||||
)
|
||||
})?;
|
||||
|
||||
mem::forget(result);
|
||||
|
||||
Ok(JsStringUtf8 {
|
||||
inner: self,
|
||||
buf: mem::ManuallyDrop::new(unsafe {
|
||||
Vec::from_raw_parts(
|
||||
buf_ptr as *mut _,
|
||||
written_char_count as _,
|
||||
written_char_count as _,
|
||||
)
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn into_utf8_ref(self) -> Result<Ref<JsStringUtf8>> {
|
||||
Ref::new(self.0, 1, self.into_utf8()?)
|
||||
}
|
||||
|
||||
pub fn into_utf16(self) -> Result<JsStringUtf16> {
|
||||
let mut written_char_count: u64 = 0;
|
||||
let len = self.utf16_len()? + 1;
|
||||
let mut result = Vec::with_capacity(len);
|
||||
let buf_ptr = result.as_mut_ptr();
|
||||
check_status(unsafe {
|
||||
sys::napi_get_value_string_utf16(
|
||||
self.0.env,
|
||||
self.0.value,
|
||||
buf_ptr,
|
||||
len as u64,
|
||||
&mut written_char_count,
|
||||
)
|
||||
})?;
|
||||
mem::forget(result);
|
||||
|
||||
Ok(JsStringUtf16 {
|
||||
inner: self,
|
||||
buf: mem::ManuallyDrop::new(unsafe {
|
||||
Vec::from_raw_parts(buf_ptr, written_char_count as _, written_char_count as _)
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn into_utf16_ref(self) -> Result<Ref<JsStringUtf16>> {
|
||||
Ref::new(self.0, 1, self.into_utf16()?)
|
||||
}
|
||||
|
||||
pub fn into_latin1(self) -> Result<JsStringLatin1> {
|
||||
let mut written_char_count: u64 = 0;
|
||||
let len = self.latin1_len()? + 1;
|
||||
let mut result = Vec::with_capacity(len);
|
||||
let buf_ptr = result.as_mut_ptr();
|
||||
check_status(unsafe {
|
||||
sys::napi_get_value_string_latin1(
|
||||
self.0.env,
|
||||
self.0.value,
|
||||
buf_ptr,
|
||||
len as u64,
|
||||
&mut written_char_count,
|
||||
)
|
||||
})?;
|
||||
|
||||
mem::forget(result);
|
||||
|
||||
Ok(JsStringLatin1 {
|
||||
inner: self,
|
||||
buf: mem::ManuallyDrop::new(unsafe {
|
||||
Vec::from_raw_parts(
|
||||
buf_ptr as *mut _,
|
||||
written_char_count as _,
|
||||
written_char_count as _,
|
||||
)
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn into_latin1_ref(self) -> Result<Ref<JsStringLatin1>> {
|
||||
Ref::new(self.0, 1, self.into_latin1()?)
|
||||
}
|
||||
}
|
57
napi/src/js_values/string/utf16.rs
Normal file
57
napi/src/js_values/string/utf16.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
|
||||
use crate::{Error, JsString, Result, Status};
|
||||
|
||||
pub struct JsStringUtf16 {
|
||||
pub(crate) inner: JsString,
|
||||
pub(crate) buf: mem::ManuallyDrop<Vec<u16>>,
|
||||
}
|
||||
|
||||
impl JsStringUtf16 {
|
||||
pub fn as_str(&self) -> Result<String> {
|
||||
String::from_utf16(self.as_slice())
|
||||
.map_err(|e| Error::new(Status::InvalidArg, format!("{}", e)))
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u16] {
|
||||
self.buf.as_slice()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.buf.len()
|
||||
}
|
||||
|
||||
pub fn into_value(self) -> JsString {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<JsStringUtf16> for String {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: JsStringUtf16) -> Result<String> {
|
||||
value.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for JsStringUtf16 {
|
||||
type Target = [u16];
|
||||
|
||||
fn deref(&self) -> &[u16] {
|
||||
self.buf.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Vec<u16>> for JsStringUtf16 {
|
||||
fn as_ref(&self) -> &Vec<u16> {
|
||||
&self.buf
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JsStringUtf16> for Vec<u16> {
|
||||
fn from(value: JsStringUtf16) -> Self {
|
||||
value.as_slice().to_vec()
|
||||
}
|
||||
}
|
51
napi/src/js_values/string/utf8.rs
Normal file
51
napi/src/js_values/string/utf8.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::str;
|
||||
|
||||
use crate::{Error, JsString, Result, Status};
|
||||
|
||||
pub struct JsStringUtf8 {
|
||||
pub(crate) inner: JsString,
|
||||
pub(crate) buf: ManuallyDrop<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl JsStringUtf8 {
|
||||
pub fn as_str(&self) -> Result<&str> {
|
||||
str::from_utf8(self.buf.as_slice())
|
||||
.map_err(|e| Error::new(Status::InvalidArg, format!("{}", e)))
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
&self.buf
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.buf.len()
|
||||
}
|
||||
|
||||
pub fn to_owned(self) -> Result<String> {
|
||||
Ok(self.as_str()?.to_owned())
|
||||
}
|
||||
|
||||
pub fn take(self) -> Vec<u8> {
|
||||
self.as_slice().to_vec()
|
||||
}
|
||||
|
||||
pub fn into_value(self) -> JsString {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<JsStringUtf8> for String {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: JsStringUtf8) -> Result<String> {
|
||||
Ok(value.as_str()?.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JsStringUtf8> for Vec<u8> {
|
||||
fn from(value: JsStringUtf8) -> Self {
|
||||
value.take()
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
use super::Value;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct JsUndefined(pub(crate) Value);
|
||||
|
|
|
@ -1,35 +1,62 @@
|
|||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
|
||||
use super::NapiValue;
|
||||
use crate::{sys, Status};
|
||||
use super::{check_status, Value};
|
||||
use crate::{sys, Env, Result};
|
||||
|
||||
pub struct Ref<T: NapiValue> {
|
||||
pub(crate) raw_env: sys::napi_env,
|
||||
pub(crate) ref_value: sys::napi_ref,
|
||||
_phantom: PhantomData<T>,
|
||||
pub struct Ref<T> {
|
||||
pub(crate) raw_ref: sys::napi_ref,
|
||||
count: u32,
|
||||
inner: T,
|
||||
}
|
||||
|
||||
impl<T: NapiValue> Ref<T> {
|
||||
pub fn new(raw_env: sys::napi_env, ref_value: sys::napi_ref) -> Ref<T> {
|
||||
Ref {
|
||||
raw_env,
|
||||
ref_value,
|
||||
_phantom: PhantomData,
|
||||
unsafe impl<T> Send for Ref<T> {}
|
||||
unsafe impl<T> Sync for Ref<T> {}
|
||||
|
||||
impl<T> Ref<T> {
|
||||
pub(crate) fn new(js_value: Value, ref_count: u32, inner: T) -> Result<Ref<T>> {
|
||||
let mut raw_ref = ptr::null_mut();
|
||||
let initial_ref_count = 1;
|
||||
check_status(unsafe {
|
||||
sys::napi_create_reference(
|
||||
js_value.env,
|
||||
js_value.value,
|
||||
initial_ref_count,
|
||||
&mut raw_ref,
|
||||
)
|
||||
})?;
|
||||
Ok(Ref {
|
||||
raw_ref,
|
||||
count: ref_count,
|
||||
inner,
|
||||
})
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn unref(mut self, env: Env) -> Result<u32> {
|
||||
check_status(unsafe { sys::napi_reference_unref(env.0, self.raw_ref, &mut self.count) })?;
|
||||
|
||||
if self.count == 0 {
|
||||
check_status(unsafe { sys::napi_delete_reference(env.0, self.raw_ref) })?;
|
||||
}
|
||||
Ok(self.count)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: NapiValue> Drop for Ref<T> {
|
||||
impl<T> Deref for Ref<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
impl<T> Drop for Ref<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let mut ref_count = 0;
|
||||
let status = sys::napi_reference_unref(self.raw_env, self.ref_value, &mut ref_count);
|
||||
debug_assert!(Status::from(status) == Status::Ok);
|
||||
|
||||
if ref_count == 0 {
|
||||
let status = sys::napi_delete_reference(self.raw_env, self.ref_value);
|
||||
debug_assert!(Status::from(status) == Status::Ok);
|
||||
}
|
||||
}
|
||||
debug_assert_eq!(
|
||||
self.count, 0,
|
||||
"Ref count is not equal to 0 while dropping Ref, potential memory leak"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ macro_rules! register_module {
|
|||
let hook_result = Ok(());
|
||||
|
||||
match hook_result.and_then(move |_| result) {
|
||||
Ok(_) => cjs_module.exports.raw_value(),
|
||||
Ok(_) => cjs_module.exports.raw(),
|
||||
Err(e) => {
|
||||
unsafe {
|
||||
sys::napi_throw_error(
|
||||
|
|
|
@ -106,7 +106,7 @@ unsafe extern "C" fn call_js_cb<T, V: NapiValue>(
|
|||
let js_value_to_resolve = value.and_then(move |v| (resolver)(&mut env, v));
|
||||
match js_value_to_resolve {
|
||||
Ok(v) => {
|
||||
let status = sys::napi_resolve_deferred(raw_env, deferred, v.raw_value());
|
||||
let status = sys::napi_resolve_deferred(raw_env, deferred, v.raw());
|
||||
debug_assert!(
|
||||
status == sys::napi_status::napi_ok,
|
||||
"Resolve promise failed"
|
||||
|
|
|
@ -7,5 +7,5 @@ pub trait Task: Send {
|
|||
|
||||
fn compute(&mut self) -> Result<Self::Output>;
|
||||
|
||||
fn resolve(&self, env: &mut Env, output: Self::Output) -> Result<Self::JsValue>;
|
||||
fn resolve(self, env: Env, output: Self::Output) -> Result<Self::JsValue>;
|
||||
}
|
||||
|
|
|
@ -6,3 +6,9 @@ test('should be able to spawn thread and return promise', async (t) => {
|
|||
const result = await bindings.testSpawnThread(20)
|
||||
t.is(result, 6765)
|
||||
})
|
||||
|
||||
test('should be able to spawn thread with ref value', async (t) => {
|
||||
const fixture = 'hello'
|
||||
const result = await bindings.testSpawnThreadWithRef(Buffer.from(fixture))
|
||||
t.is(result, fixture.length)
|
||||
})
|
||||
|
|
|
@ -4,13 +4,13 @@ use napi::{CallContext, Error, JsBuffer, JsNumber, JsString, Module, Result, Sta
|
|||
|
||||
#[js_function(1)]
|
||||
pub fn get_buffer_length(ctx: CallContext) -> Result<JsNumber> {
|
||||
let buffer = ctx.get::<JsBuffer>(0)?;
|
||||
let buffer = ctx.get::<JsBuffer>(0)?.into_value()?;
|
||||
ctx.env.create_uint32((&buffer).len() as u32)
|
||||
}
|
||||
|
||||
#[js_function(1)]
|
||||
pub fn buffer_to_string(ctx: CallContext) -> Result<JsString> {
|
||||
let buffer = ctx.get::<JsBuffer>(0)?;
|
||||
let buffer = ctx.get::<JsBuffer>(0)?.into_value()?;
|
||||
ctx.env.create_string(
|
||||
str::from_utf8(&buffer).map_err(|e| Error::new(Status::StringExpected, format!("{}", e)))?,
|
||||
)
|
||||
|
|
|
@ -11,7 +11,7 @@ pub fn either_number_string(ctx: CallContext) -> Result<Either<JsNumber, JsStrin
|
|||
ctx.env.create_uint32(n + 100).map(Either::A)
|
||||
}
|
||||
Either::B(s) => {
|
||||
let content = format!("Either::B({})", s.as_str()?);
|
||||
let content = format!("Either::B({})", s.into_utf8()?.as_str()?);
|
||||
ctx.env.create_string_from_std(content).map(Either::B)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ fn test_throw_with_reason(ctx: CallContext) -> Result<JsUnknown> {
|
|||
let reason = ctx.get::<JsString>(0)?;
|
||||
Err(Error::new(
|
||||
Status::GenericFailure,
|
||||
reason.as_str()?.to_owned(),
|
||||
reason.into_utf8()?.as_str()?.to_owned(),
|
||||
))
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ use napi::{CallContext, Error, JsObject, JsString, Module, Result, Status};
|
|||
pub fn uv_read_file(ctx: CallContext) -> Result<JsObject> {
|
||||
let path = ctx.get::<JsString>(0)?;
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
let p = path.as_str()?.to_owned();
|
||||
let p = path.into_utf8()?.to_owned()?;
|
||||
thread::spawn(|| {
|
||||
let res = fs::read(p).map_err(|e| Error::new(Status::Unknown, format!("{}", e)));
|
||||
sender.send(res).expect("Send data failed");
|
||||
|
@ -18,7 +18,7 @@ pub fn uv_read_file(ctx: CallContext) -> Result<JsObject> {
|
|||
receiver
|
||||
.map_err(|e| Error::new(Status::Unknown, format!("{}", e)))
|
||||
.map(|x| x.and_then(|x| x)),
|
||||
|&mut env, data| env.create_buffer_with_data(data),
|
||||
|&mut env, data| env.create_buffer_with_data(data).map(|v| v.into_raw()),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -85,22 +85,21 @@ impl ToJs for HandleBuffer {
|
|||
async fn read_file_content(filepath: &Path) -> Result<Vec<u8>> {
|
||||
tokio::fs::read(filepath)
|
||||
.await
|
||||
.map_err(|_| Error::new(Status::Unknown, "failed to read file".to_owned()))
|
||||
.map_err(|e| Error::new(Status::Unknown, format!("{}", e)))
|
||||
}
|
||||
|
||||
#[js_function(2)]
|
||||
pub fn test_tokio_readfile(ctx: CallContext) -> Result<JsUndefined> {
|
||||
let js_filepath = ctx.get::<JsString>(0)?;
|
||||
let js_func = ctx.get::<JsFunction>(1)?;
|
||||
let path_str = js_filepath.as_str()?;
|
||||
let path_str = js_filepath.into_utf8()?.to_owned()?;
|
||||
|
||||
let to_js = HandleBuffer;
|
||||
let tsfn = ThreadsafeFunction::create(ctx.env, js_func, to_js, 0)?;
|
||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
rt.block_on(async move {
|
||||
let mut filepath = Path::new(path_str);
|
||||
let ret = read_file_content(&mut filepath).await;
|
||||
let ret = read_file_content(&Path::new(&path_str)).await;
|
||||
let _ = tsfn.call(ret, ThreadsafeFunctionCallMode::Blocking);
|
||||
tsfn
|
||||
.release(ThreadsafeFunctionReleaseMode::Release)
|
||||
|
|
|
@ -31,14 +31,18 @@ fn test_get_named_property(ctx: CallContext) -> Result<JsUnknown> {
|
|||
fn test_has_named_property(ctx: CallContext) -> Result<JsBoolean> {
|
||||
let obj = ctx.get::<JsObject>(0)?;
|
||||
let key = ctx.get::<JsString>(1)?;
|
||||
ctx.env.get_boolean(obj.has_named_property(key.as_str()?)?)
|
||||
ctx
|
||||
.env
|
||||
.get_boolean(obj.has_named_property(key.into_utf8()?.as_str()?)?)
|
||||
}
|
||||
|
||||
#[js_function(2)]
|
||||
fn test_has_own_property(ctx: CallContext) -> Result<JsBoolean> {
|
||||
let obj = ctx.get::<JsObject>(0)?;
|
||||
let key = ctx.get::<JsString>(1)?;
|
||||
ctx.env.get_boolean(obj.has_own_property(key.as_str()?)?)
|
||||
ctx
|
||||
.env
|
||||
.get_boolean(obj.has_own_property(key.into_utf8()?.as_str()?)?)
|
||||
}
|
||||
|
||||
#[js_function(2)]
|
||||
|
@ -52,7 +56,9 @@ fn test_has_own_property_js(ctx: CallContext) -> Result<JsBoolean> {
|
|||
fn test_has_property(ctx: CallContext) -> Result<JsBoolean> {
|
||||
let obj = ctx.get::<JsObject>(0)?;
|
||||
let key = ctx.get::<JsString>(1)?;
|
||||
ctx.env.get_boolean(obj.has_property(key.as_str()?)?)
|
||||
ctx
|
||||
.env
|
||||
.get_boolean(obj.has_property(key.into_utf8()?.as_str()?)?)
|
||||
}
|
||||
|
||||
#[js_function(2)]
|
||||
|
@ -75,7 +81,7 @@ fn test_delete_named_property(ctx: CallContext) -> Result<JsBoolean> {
|
|||
let key = ctx.get::<JsString>(1)?;
|
||||
ctx
|
||||
.env
|
||||
.get_boolean(obj.delete_named_property(key.as_str()?)?)
|
||||
.get_boolean(obj.delete_named_property(key.into_utf8()?.as_str()?)?)
|
||||
}
|
||||
|
||||
#[js_function(2)]
|
||||
|
|
|
@ -3,14 +3,17 @@ use napi::{CallContext, JsString, Module, Result};
|
|||
#[js_function(1)]
|
||||
fn concat_string(ctx: CallContext) -> Result<JsString> {
|
||||
let in_string = ctx.get::<JsString>(0)?;
|
||||
let out_string = format!("{} + Rust 🦀 string!", in_string.as_str()?);
|
||||
let out_string = format!("{} + Rust 🦀 string!", in_string.into_utf8()?.as_str()?);
|
||||
ctx.env.create_string_from_std(out_string)
|
||||
}
|
||||
|
||||
#[js_function(1)]
|
||||
fn concat_latin1_string(ctx: CallContext) -> Result<JsString> {
|
||||
let in_string = ctx.get::<JsString>(0)?;
|
||||
let out_string = format!("{} + Rust 🦀 string!", in_string.as_latin1_string()?);
|
||||
let out_string = format!(
|
||||
"{} + Rust 🦀 string!",
|
||||
in_string.into_latin1()?.into_latin1_string()?
|
||||
);
|
||||
ctx.env.create_string_from_std(out_string)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use std::convert::TryInto;
|
||||
|
||||
use napi::{CallContext, Env, JsNumber, JsObject, Module, Result, Task};
|
||||
use napi::{
|
||||
CallContext, Env, JsBuffer, JsBufferValue, JsNumber, JsObject, Module, Ref, Result, Task,
|
||||
};
|
||||
|
||||
struct ComputeFib {
|
||||
n: u32,
|
||||
|
@ -20,7 +22,7 @@ impl Task for ComputeFib {
|
|||
Ok(fibonacci_native(self.n))
|
||||
}
|
||||
|
||||
fn resolve(&self, env: &mut Env, output: Self::Output) -> Result<Self::JsValue> {
|
||||
fn resolve(self, env: Env, output: Self::Output) -> Result<Self::JsValue> {
|
||||
env.create_uint32(output)
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +43,40 @@ fn test_spawn_thread(ctx: CallContext) -> Result<JsObject> {
|
|||
Ok(async_promise.promise_object())
|
||||
}
|
||||
|
||||
struct CountBufferLength {
|
||||
data: Ref<JsBufferValue>,
|
||||
}
|
||||
|
||||
impl CountBufferLength {
|
||||
pub fn new(data: Ref<JsBufferValue>) -> Self {
|
||||
Self { data }
|
||||
}
|
||||
}
|
||||
|
||||
impl Task for CountBufferLength {
|
||||
type Output = usize;
|
||||
type JsValue = JsNumber;
|
||||
|
||||
fn compute(&mut self) -> Result<Self::Output> {
|
||||
Ok((&self.data).len())
|
||||
}
|
||||
|
||||
fn resolve(self, env: Env, output: Self::Output) -> Result<Self::JsValue> {
|
||||
self.data.unref(env)?;
|
||||
env.create_uint32(output as _)
|
||||
}
|
||||
}
|
||||
|
||||
#[js_function(1)]
|
||||
fn test_spawn_thread_with_ref(ctx: CallContext) -> Result<JsObject> {
|
||||
let n = ctx.get::<JsBuffer>(0)?.into_ref()?;
|
||||
let task = CountBufferLength::new(n);
|
||||
let async_work_promise = ctx.env.spawn(task)?;
|
||||
Ok(async_work_promise.promise_object())
|
||||
}
|
||||
|
||||
pub fn register_js(module: &mut Module) -> Result<()> {
|
||||
module.create_named_method("testSpawnThread", test_spawn_thread)?;
|
||||
module.create_named_method("testSpawnThreadWithRef", test_spawn_thread_with_ref)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -5,20 +5,20 @@ use tokio;
|
|||
#[js_function(1)]
|
||||
pub fn test_execute_tokio_readfile(ctx: CallContext) -> Result<JsObject> {
|
||||
let js_filepath = ctx.get::<JsString>(0)?;
|
||||
let path_str = js_filepath.as_str()?;
|
||||
let path_str = js_filepath.into_utf8()?.to_owned()?;
|
||||
ctx.env.execute_tokio_future(
|
||||
tokio::fs::read(path_str.to_owned())
|
||||
tokio::fs::read(path_str)
|
||||
.map(|v| v.map_err(|e| Error::new(Status::Unknown, format!("failed to read file, {}", e)))),
|
||||
|&mut env, data| env.create_buffer_with_data(data),
|
||||
|&mut env, data| env.create_buffer_with_data(data).map(|v| v.into_raw()),
|
||||
)
|
||||
}
|
||||
|
||||
#[js_function(1)]
|
||||
pub fn error_from_tokio_future(ctx: CallContext) -> Result<JsObject> {
|
||||
let js_filepath = ctx.get::<JsString>(0)?;
|
||||
let path_str = js_filepath.as_str()?;
|
||||
let path_str = js_filepath.into_utf8()?.to_owned()?;
|
||||
ctx.env.execute_tokio_future(
|
||||
tokio::fs::read(path_str.to_owned())
|
||||
tokio::fs::read(path_str)
|
||||
.map_err(Error::from)
|
||||
.and_then(|_| async move {
|
||||
Err::<Vec<u8>, Error>(Error::new(
|
||||
|
@ -26,6 +26,6 @@ pub fn error_from_tokio_future(ctx: CallContext) -> Result<JsObject> {
|
|||
"Error from tokio future".to_owned(),
|
||||
))
|
||||
}),
|
||||
|&mut env, data| env.create_buffer_with_data(data),
|
||||
|&mut env, data| env.create_buffer_with_data(data).map(|v| v.into_raw()),
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue