chore: specified dependencies versions
This commit is contained in:
parent
9570899025
commit
d36c303dec
29 changed files with 543 additions and 85 deletions
|
@ -1,5 +1,5 @@
|
||||||
use proc_macro2::Ident;
|
use proc_macro2::Ident;
|
||||||
use syn::Attribute;
|
use syn::{Attribute, Type};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct NapiFn {
|
pub struct NapiFn {
|
||||||
|
@ -76,6 +76,7 @@ pub struct NapiImpl {
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub js_name: String,
|
pub js_name: String,
|
||||||
pub items: Vec<NapiFn>,
|
pub items: Vec<NapiFn>,
|
||||||
|
pub task_output_type: Option<Type>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
@ -76,6 +76,13 @@ impl TryToTokens for NapiStruct {
|
||||||
|
|
||||||
impl NapiStruct {
|
impl NapiStruct {
|
||||||
fn gen_helper_mod(&self) -> TokenStream {
|
fn gen_helper_mod(&self) -> TokenStream {
|
||||||
|
if crate::typegen::r#struct::TASK_STRUCTS.with(|t| {
|
||||||
|
println!("{:?}", t);
|
||||||
|
t.borrow().get(&self.name.to_string()).is_some()
|
||||||
|
}) {
|
||||||
|
return quote! {};
|
||||||
|
}
|
||||||
|
|
||||||
let mod_name = Ident::new(
|
let mod_name = Ident::new(
|
||||||
&format!("__napi_helper__{}", self.name.to_string()),
|
&format!("__napi_helper__{}", self.name.to_string()),
|
||||||
Span::call_site(),
|
Span::call_site(),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
mod r#enum;
|
mod r#enum;
|
||||||
mod r#fn;
|
mod r#fn;
|
||||||
mod r#struct;
|
pub(crate) mod r#struct;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ static KNOWN_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
|
||||||
("i16", "number"),
|
("i16", "number"),
|
||||||
("i32", "number"),
|
("i32", "number"),
|
||||||
("i64", "number"),
|
("i64", "number"),
|
||||||
|
("f64", "number"),
|
||||||
("u8", "number"),
|
("u8", "number"),
|
||||||
("u16", "number"),
|
("u16", "number"),
|
||||||
("u32", "number"),
|
("u32", "number"),
|
||||||
|
@ -54,6 +55,9 @@ static KNOWN_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
|
||||||
("Value", "any"),
|
("Value", "any"),
|
||||||
("Map", "Record<string, any>"),
|
("Map", "Record<string, any>"),
|
||||||
("HashMap", "Record<{}, {}>"),
|
("HashMap", "Record<{}, {}>"),
|
||||||
|
("ArrayBuffer", "ArrayBuffer"),
|
||||||
|
("DataView", "DataView"),
|
||||||
|
("Date", "Date"),
|
||||||
("Buffer", "Buffer"),
|
("Buffer", "Buffer"),
|
||||||
// TODO: Vec<u8> should be Buffer, now is Array<number>
|
// TODO: Vec<u8> should be Buffer, now is Array<number>
|
||||||
("Vec", "Array<{}>"),
|
("Vec", "Array<{}>"),
|
||||||
|
@ -63,6 +67,12 @@ static KNOWN_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
|
||||||
("Either3", "{} | {} | {}"),
|
("Either3", "{} | {} | {}"),
|
||||||
("Either4", "{} | {} | {} | {}"),
|
("Either4", "{} | {} | {} | {}"),
|
||||||
("Either5", "{} | {} | {} | {} | {}"),
|
("Either5", "{} | {} | {} | {} | {}"),
|
||||||
|
("unknown", "unknown"),
|
||||||
|
("null", "null"),
|
||||||
|
("symbol", "symbol"),
|
||||||
|
("external", "object"),
|
||||||
|
("AsyncTaskAbortController", "AbortController"),
|
||||||
|
("Function", "(...args: any[]) => any"),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
map
|
map
|
||||||
|
@ -124,6 +134,15 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool) -> String {
|
||||||
|
|
||||||
if rust_ty == "Result" && is_return_ty {
|
if rust_ty == "Result" && is_return_ty {
|
||||||
ts_ty = Some(args.first().unwrap().to_owned());
|
ts_ty = Some(args.first().unwrap().to_owned());
|
||||||
|
} else if rust_ty == "AsyncTask" {
|
||||||
|
ts_ty = r#struct::TASK_STRUCTS.with(|t| {
|
||||||
|
let output_type = args.first().unwrap().to_owned();
|
||||||
|
if let Some(o) = t.borrow().get(&output_type) {
|
||||||
|
Some(format!("Promise<{}>", o))
|
||||||
|
} else {
|
||||||
|
Some("Promise<unknown>".to_owned())
|
||||||
|
}
|
||||||
|
});
|
||||||
} else if let Some(&known_ty) = KNOWN_TYPES.get(rust_ty.as_str()) {
|
} else if let Some(&known_ty) = KNOWN_TYPES.get(rust_ty.as_str()) {
|
||||||
if known_ty.contains("{}") {
|
if known_ty.contains("{}") {
|
||||||
ts_ty = Some(fill_ty(known_ty, args));
|
ts_ty = Some(fill_ty(known_ty, args));
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use super::{ToTypeDef, TypeDef};
|
use super::{ToTypeDef, TypeDef};
|
||||||
use crate::{ty_to_ts_type, NapiImpl, NapiStruct, NapiStructKind};
|
use crate::{ty_to_ts_type, NapiImpl, NapiStruct, NapiStructKind};
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
pub(crate) static TASK_STRUCTS: RefCell<HashMap<String, String>> = Default::default();
|
||||||
|
}
|
||||||
|
|
||||||
impl ToTypeDef for NapiStruct {
|
impl ToTypeDef for NapiStruct {
|
||||||
fn to_type_def(&self) -> TypeDef {
|
fn to_type_def(&self) -> TypeDef {
|
||||||
TypeDef {
|
TypeDef {
|
||||||
|
@ -17,6 +24,12 @@ impl ToTypeDef for NapiStruct {
|
||||||
|
|
||||||
impl ToTypeDef for NapiImpl {
|
impl ToTypeDef for NapiImpl {
|
||||||
fn to_type_def(&self) -> TypeDef {
|
fn to_type_def(&self) -> TypeDef {
|
||||||
|
if let Some(output_type) = &self.task_output_type {
|
||||||
|
TASK_STRUCTS.with(|t| {
|
||||||
|
t.borrow_mut()
|
||||||
|
.insert(self.js_name.clone(), ty_to_ts_type(output_type, false));
|
||||||
|
});
|
||||||
|
}
|
||||||
TypeDef {
|
TypeDef {
|
||||||
kind: "impl".to_owned(),
|
kind: "impl".to_owned(),
|
||||||
name: self.js_name.to_owned(),
|
name: self.js_name.to_owned(),
|
||||||
|
|
|
@ -18,7 +18,7 @@ type-def = ["napi-derive-backend/type-def"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
convert_case = "0.4"
|
convert_case = "0.4"
|
||||||
napi-derive-backend = {version = "1", path = "../backend"}
|
napi-derive-backend = {version = "1.0.2", path = "../backend"}
|
||||||
proc-macro2 = "1.0"
|
proc-macro2 = "1.0"
|
||||||
quote = "1.0"
|
quote = "1.0"
|
||||||
syn = {version = "1.0", features = ["fold", "full", "extra-traits"]}
|
syn = {version = "1.0", features = ["fold", "full", "extra-traits"]}
|
||||||
|
|
|
@ -15,7 +15,7 @@ use napi_derive_backend::{
|
||||||
use proc_macro2::{Ident, TokenStream, TokenTree};
|
use proc_macro2::{Ident, TokenStream, TokenTree};
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use syn::parse::{Parse, ParseStream, Result as SynResult};
|
use syn::parse::{Parse, ParseStream, Result as SynResult};
|
||||||
use syn::{Attribute, Signature, Visibility};
|
use syn::{Attribute, Signature, Type, Visibility};
|
||||||
|
|
||||||
use crate::parser::attrs::{check_recorded_struct_for_impl, record_struct};
|
use crate::parser::attrs::{check_recorded_struct_for_impl, record_struct};
|
||||||
|
|
||||||
|
@ -755,43 +755,52 @@ impl ConvertToAST for syn::ItemImpl {
|
||||||
|
|
||||||
let mut struct_js_name = struct_name.to_string();
|
let mut struct_js_name = struct_name.to_string();
|
||||||
let mut items = vec![];
|
let mut items = vec![];
|
||||||
|
let mut task_output_type = None;
|
||||||
for item in self.items.iter_mut() {
|
for item in self.items.iter_mut() {
|
||||||
let method = match item {
|
if let Some(method) = match item {
|
||||||
syn::ImplItem::Method(m) => m,
|
syn::ImplItem::Method(m) => Some(m),
|
||||||
|
syn::ImplItem::Type(m) => {
|
||||||
|
if m.ident == *"JsValue" {
|
||||||
|
if let Type::Path(_) = &m.ty {
|
||||||
|
task_output_type = Some(m.ty.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
bail_span!(item, "unsupported impl item in #[napi]")
|
bail_span!(item, "unsupported impl item in #[napi]")
|
||||||
}
|
}
|
||||||
};
|
} {
|
||||||
let opts = BindgenAttrs::find(&mut method.attrs)?;
|
let opts = BindgenAttrs::find(&mut method.attrs)?;
|
||||||
|
|
||||||
// it'd better only care methods decorated with `#[napi]` attribute
|
// it'd better only care methods decorated with `#[napi]` attribute
|
||||||
if !opts.exists {
|
if !opts.exists {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if opts.constructor().is_some() {
|
|
||||||
struct_js_name = check_recorded_struct_for_impl(&struct_name, &opts)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let vis = method.vis.clone();
|
|
||||||
|
|
||||||
match &vis {
|
|
||||||
Visibility::Public(_) => {}
|
|
||||||
_ => {
|
|
||||||
bail_span!(method.sig.ident, "only pub method supported by #[napi].",);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.constructor().is_some() {
|
||||||
|
struct_js_name = check_recorded_struct_for_impl(&struct_name, &opts)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let vis = method.vis.clone();
|
||||||
|
|
||||||
|
match &vis {
|
||||||
|
Visibility::Public(_) => {}
|
||||||
|
_ => {
|
||||||
|
bail_span!(method.sig.ident, "only pub method supported by #[napi].",);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let func = napi_fn_from_decl(
|
||||||
|
method.sig.clone(),
|
||||||
|
&opts,
|
||||||
|
method.attrs.clone(),
|
||||||
|
vis,
|
||||||
|
Some(&struct_name),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
items.push(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
let func = napi_fn_from_decl(
|
|
||||||
method.sig.clone(),
|
|
||||||
&opts,
|
|
||||||
method.attrs.clone(),
|
|
||||||
vis,
|
|
||||||
Some(&struct_name),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
items.push(func);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Napi {
|
Ok(Napi {
|
||||||
|
@ -800,6 +809,7 @@ impl ConvertToAST for syn::ItemImpl {
|
||||||
name: struct_name,
|
name: struct_name,
|
||||||
js_name: struct_js_name,
|
js_name: struct_js_name,
|
||||||
items,
|
items,
|
||||||
|
task_output_type,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ tokio_rt = ["tokio", "once_cell", "napi4"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ctor = "0.1"
|
ctor = "0.1"
|
||||||
napi-sys = {version = "1", path = "../sys"}
|
napi-sys = {version = "1.1.2", path = "../sys"}
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = {version = "0.3.9", features = ["winuser", "minwindef", "ntdef", "libloaderapi"]}
|
winapi = {version = "0.3.9", features = ["winuser", "minwindef", "ntdef", "libloaderapi"]}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::raw::{c_char, c_void};
|
use std::os::raw::c_void;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::{ffi::CString, rc::Rc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
check_status,
|
bindgen_runtime::ToNapiValue, check_status, js_values::NapiValue, sys, Env, JsError, JsObject,
|
||||||
js_values::{NapiRaw, NapiValue},
|
Result, Task,
|
||||||
sys, Env, JsError, JsObject, Result, Task,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AsyncWork<T: Task> {
|
struct AsyncWork<T: Task> {
|
||||||
|
@ -13,46 +14,53 @@ struct AsyncWork<T: Task> {
|
||||||
deferred: sys::napi_deferred,
|
deferred: sys::napi_deferred,
|
||||||
value: Result<mem::MaybeUninit<T::Output>>,
|
value: Result<mem::MaybeUninit<T::Output>>,
|
||||||
napi_async_work: sys::napi_async_work,
|
napi_async_work: sys::napi_async_work,
|
||||||
|
abort: Rc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AsyncWorkPromise<'env> {
|
pub struct AsyncWorkPromise {
|
||||||
napi_async_work: sys::napi_async_work,
|
pub(crate) napi_async_work: sys::napi_async_work,
|
||||||
raw_promise: sys::napi_value,
|
raw_promise: sys::napi_value,
|
||||||
env: &'env Env,
|
pub(crate) deferred: sys::napi_deferred,
|
||||||
|
env: sys::napi_env,
|
||||||
|
// share with AsyncWork
|
||||||
|
pub(crate) abort: Rc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'env> AsyncWorkPromise<'env> {
|
impl AsyncWorkPromise {
|
||||||
pub fn promise_object(&self) -> JsObject {
|
pub fn promise_object(&self) -> JsObject {
|
||||||
unsafe { JsObject::from_raw_unchecked(self.env.0, self.raw_promise) }
|
unsafe { JsObject::from_raw_unchecked(self.env, self.raw_promise) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cancel(self) -> Result<()> {
|
pub fn cancel(&self) -> Result<()> {
|
||||||
check_status!(unsafe { sys::napi_cancel_async_work(self.env.0, self.napi_async_work) })
|
// must be happened in the main thread, relaxed is enough
|
||||||
|
self.abort.store(true, Ordering::Relaxed);
|
||||||
|
check_status!(unsafe { sys::napi_cancel_async_work(self.env, self.napi_async_work) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run<T: Task>(env: &Env, task: T) -> Result<AsyncWorkPromise<'_>> {
|
pub fn run<T: Task>(
|
||||||
|
env: sys::napi_env,
|
||||||
|
task: T,
|
||||||
|
abort_status: Option<Rc<AtomicBool>>,
|
||||||
|
) -> Result<AsyncWorkPromise> {
|
||||||
let mut raw_resource = ptr::null_mut();
|
let mut raw_resource = ptr::null_mut();
|
||||||
check_status!(unsafe { sys::napi_create_object(env.0, &mut raw_resource) })?;
|
check_status!(unsafe { sys::napi_create_object(env, &mut raw_resource) })?;
|
||||||
let mut raw_promise = ptr::null_mut();
|
let mut raw_promise = ptr::null_mut();
|
||||||
let mut deferred = ptr::null_mut();
|
let mut deferred = ptr::null_mut();
|
||||||
check_status!(unsafe { sys::napi_create_promise(env.0, &mut deferred, &mut raw_promise) })?;
|
check_status!(unsafe { sys::napi_create_promise(env, &mut deferred, &mut raw_promise) })?;
|
||||||
let mut raw_name = ptr::null_mut();
|
let task_abort = abort_status.unwrap_or_else(|| Rc::new(AtomicBool::new(false)));
|
||||||
let s = "napi_rs_async_work";
|
|
||||||
check_status!(unsafe {
|
|
||||||
sys::napi_create_string_utf8(env.0, s.as_ptr() as *const c_char, s.len(), &mut raw_name)
|
|
||||||
})?;
|
|
||||||
let result = Box::leak(Box::new(AsyncWork {
|
let result = Box::leak(Box::new(AsyncWork {
|
||||||
inner_task: task,
|
inner_task: task,
|
||||||
deferred,
|
deferred,
|
||||||
value: Ok(mem::MaybeUninit::zeroed()),
|
value: Ok(mem::MaybeUninit::zeroed()),
|
||||||
napi_async_work: ptr::null_mut(),
|
napi_async_work: ptr::null_mut(),
|
||||||
|
abort: task_abort.clone(),
|
||||||
}));
|
}));
|
||||||
check_status!(unsafe {
|
check_status!(unsafe {
|
||||||
sys::napi_create_async_work(
|
sys::napi_create_async_work(
|
||||||
env.0,
|
env,
|
||||||
raw_resource,
|
raw_resource,
|
||||||
raw_name,
|
CString::new("napi_rs_async_work")?.as_ptr() as *mut _,
|
||||||
Some(execute::<T> as unsafe extern "C" fn(env: sys::napi_env, data: *mut c_void)),
|
Some(execute::<T> as unsafe extern "C" fn(env: sys::napi_env, data: *mut c_void)),
|
||||||
Some(
|
Some(
|
||||||
complete::<T>
|
complete::<T>
|
||||||
|
@ -62,11 +70,13 @@ pub fn run<T: Task>(env: &Env, task: T) -> Result<AsyncWorkPromise<'_>> {
|
||||||
&mut result.napi_async_work,
|
&mut result.napi_async_work,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
check_status!(unsafe { sys::napi_queue_async_work(env.0, result.napi_async_work) })?;
|
check_status!(unsafe { sys::napi_queue_async_work(env, result.napi_async_work) })?;
|
||||||
Ok(AsyncWorkPromise {
|
Ok(AsyncWorkPromise {
|
||||||
napi_async_work: result.napi_async_work,
|
napi_async_work: result.napi_async_work,
|
||||||
raw_promise,
|
raw_promise,
|
||||||
|
deferred,
|
||||||
env,
|
env,
|
||||||
|
abort: task_abort,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,11 +88,16 @@ unsafe impl<T: Task> Sync for AsyncWork<T> {}
|
||||||
/// So it actually could do nothing here, because `execute` function is called in the other thread mostly.
|
/// 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) {
|
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 mut work = Box::from_raw(data as *mut AsyncWork<T>);
|
||||||
|
if work.abort.load(Ordering::Relaxed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let _ = mem::replace(
|
let _ = mem::replace(
|
||||||
&mut work.value,
|
&mut work.value,
|
||||||
work.inner_task.compute().map(mem::MaybeUninit::new),
|
work.inner_task.compute().map(mem::MaybeUninit::new),
|
||||||
);
|
);
|
||||||
Box::leak(work);
|
if !work.abort.load(Ordering::Relaxed) {
|
||||||
|
Box::leak(work);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn complete<T: Task>(
|
unsafe extern "C" fn complete<T: Task>(
|
||||||
|
@ -101,10 +116,13 @@ unsafe extern "C" fn complete<T: Task>(
|
||||||
}
|
}
|
||||||
Err(e) => work.inner_task.reject(Env::from_raw(env), e),
|
Err(e) => work.inner_task.reject(Env::from_raw(env), e),
|
||||||
};
|
};
|
||||||
match check_status!(status).and_then(move |_| value) {
|
match check_status!(status)
|
||||||
|
.and_then(move |_| value)
|
||||||
|
.and_then(|v| ToNapiValue::to_napi_value(env, v))
|
||||||
|
{
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
let status = sys::napi_resolve_deferred(env, deferred, v.raw());
|
let status = sys::napi_resolve_deferred(env, deferred, v);
|
||||||
debug_assert!(status == sys::Status::napi_ok, "Reject promise failed");
|
debug_assert!(status == sys::Status::napi_ok, "Resolve promise failed");
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let status = sys::napi_reject_deferred(env, deferred, JsError::from(e).into_value(env));
|
let status = sys::napi_reject_deferred(env, deferred, JsError::from(e).into_value(env));
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{check_status, sys, Error, JsUnknown, Result, Status, ValueType};
|
use crate::{check_status, sys, Error, JsUnknown, NapiRaw, NapiValue, Result, Status, ValueType};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
mod array;
|
mod array;
|
||||||
|
@ -12,6 +12,7 @@ mod object;
|
||||||
#[cfg(feature = "serde-json")]
|
#[cfg(feature = "serde-json")]
|
||||||
mod serde;
|
mod serde;
|
||||||
mod string;
|
mod string;
|
||||||
|
mod task;
|
||||||
|
|
||||||
pub use array::*;
|
pub use array::*;
|
||||||
pub use buffer::*;
|
pub use buffer::*;
|
||||||
|
@ -19,6 +20,7 @@ pub use either::*;
|
||||||
pub use nil::*;
|
pub use nil::*;
|
||||||
pub use object::*;
|
pub use object::*;
|
||||||
pub use string::*;
|
pub use string::*;
|
||||||
|
pub use task::*;
|
||||||
|
|
||||||
#[cfg(feature = "latin1")]
|
#[cfg(feature = "latin1")]
|
||||||
pub use string::latin1_string::*;
|
pub use string::latin1_string::*;
|
||||||
|
@ -36,9 +38,25 @@ pub trait ToNapiValue {
|
||||||
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value>;
|
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToNapiValue for JsUnknown {
|
impl TypeName for JsUnknown {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> ValueType {
|
||||||
|
ValueType::Unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: NapiRaw> ToNapiValue for T {
|
||||||
unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
|
unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
|
||||||
Ok(val.0.value)
|
Ok(NapiRaw::raw(&val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: NapiValue> FromNapiValue for T {
|
||||||
|
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
|
||||||
|
Ok(T::from_raw_unchecked(env, napi_val))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,16 +67,6 @@ pub trait FromNapiValue: Sized {
|
||||||
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self>;
|
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromNapiValue for JsUnknown {
|
|
||||||
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
|
|
||||||
Ok(JsUnknown(crate::Value {
|
|
||||||
env,
|
|
||||||
value: napi_val,
|
|
||||||
value_type: crate::ValueType::Unknown,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait FromNapiRef {
|
pub trait FromNapiRef {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
|
159
crates/napi/src/bindgen_runtime/js_values/task.rs
Normal file
159
crates/napi/src/bindgen_runtime/js_values/task.rs
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
use std::ffi::c_void;
|
||||||
|
use std::ptr;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
|
||||||
|
|
||||||
|
use super::{FromNapiValue, ToNapiValue, TypeName};
|
||||||
|
use crate::{async_work, check_status, Env, Error, JsError, JsObject, NapiValue, Status, Task};
|
||||||
|
|
||||||
|
pub struct AsyncTask<T: Task> {
|
||||||
|
inner: T,
|
||||||
|
abort_controller: Option<AsyncTaskAbortController>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Task> TypeName for T {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"AsyncTask"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> crate::ValueType {
|
||||||
|
crate::ValueType::Object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Task> AsyncTask<T> {
|
||||||
|
pub fn new(task: T) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: task,
|
||||||
|
abort_controller: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_abort_controller(task: T, abort_controller: AsyncTaskAbortController) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: task,
|
||||||
|
abort_controller: Some(abort_controller),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://developer.mozilla.org/zh-CN/docs/Web/API/AbortController
|
||||||
|
pub struct AsyncTaskAbortController {
|
||||||
|
raw_work: Rc<AtomicPtr<napi_sys::napi_async_work__>>,
|
||||||
|
raw_deferred: Rc<AtomicPtr<napi_sys::napi_deferred__>>,
|
||||||
|
abort: Rc<AtomicBool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromNapiValue for AsyncTaskAbortController {
|
||||||
|
unsafe fn from_napi_value(
|
||||||
|
env: napi_sys::napi_env,
|
||||||
|
napi_val: napi_sys::napi_value,
|
||||||
|
) -> crate::Result<Self> {
|
||||||
|
let raw_abort_controller = JsObject::from_raw_unchecked(env, napi_val);
|
||||||
|
let mut signal = raw_abort_controller.get_named_property::<JsObject>("signal")?;
|
||||||
|
let async_work_inner: Rc<AtomicPtr<napi_sys::napi_async_work__>> =
|
||||||
|
Rc::new(AtomicPtr::new(ptr::null_mut()));
|
||||||
|
let raw_promise: Rc<AtomicPtr<napi_sys::napi_deferred__>> =
|
||||||
|
Rc::new(AtomicPtr::new(ptr::null_mut()));
|
||||||
|
let abort_status = Rc::new(AtomicBool::new(false));
|
||||||
|
let abort_controller = AsyncTaskAbortController {
|
||||||
|
raw_work: async_work_inner.clone(),
|
||||||
|
raw_deferred: raw_promise.clone(),
|
||||||
|
abort: abort_status.clone(),
|
||||||
|
};
|
||||||
|
let js_env = Env::from_raw(env);
|
||||||
|
check_status!(napi_sys::napi_wrap(
|
||||||
|
env,
|
||||||
|
signal.0.value,
|
||||||
|
Box::into_raw(Box::new(abort_controller)) as *mut _,
|
||||||
|
Some(async_task_abort_controller_finalize),
|
||||||
|
ptr::null_mut(),
|
||||||
|
ptr::null_mut(),
|
||||||
|
))?;
|
||||||
|
signal.set_named_property("onabort", js_env.create_function("onabort", on_abort)?)?;
|
||||||
|
Ok(AsyncTaskAbortController {
|
||||||
|
raw_work: async_work_inner,
|
||||||
|
raw_deferred: raw_promise,
|
||||||
|
abort: abort_status,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn on_abort(
|
||||||
|
env: napi_sys::napi_env,
|
||||||
|
callback_info: napi_sys::napi_callback_info,
|
||||||
|
) -> napi_sys::napi_value {
|
||||||
|
let mut this = ptr::null_mut();
|
||||||
|
unsafe {
|
||||||
|
let get_cb_info_status = napi_sys::napi_get_cb_info(
|
||||||
|
env,
|
||||||
|
callback_info,
|
||||||
|
&mut 0,
|
||||||
|
ptr::null_mut(),
|
||||||
|
&mut this,
|
||||||
|
ptr::null_mut(),
|
||||||
|
);
|
||||||
|
debug_assert_eq!(
|
||||||
|
get_cb_info_status,
|
||||||
|
napi_sys::Status::napi_ok,
|
||||||
|
"{}",
|
||||||
|
"Get callback info in AbortController abort callback failed"
|
||||||
|
);
|
||||||
|
let mut async_task = ptr::null_mut();
|
||||||
|
let status = napi_sys::napi_unwrap(env, this, &mut async_task);
|
||||||
|
debug_assert_eq!(
|
||||||
|
status,
|
||||||
|
napi_sys::Status::napi_ok,
|
||||||
|
"{}",
|
||||||
|
"Unwrap async_task from AbortSignal failed"
|
||||||
|
);
|
||||||
|
let abort_controller = Box::leak(Box::from_raw(async_task as *mut AsyncTaskAbortController));
|
||||||
|
let raw_async_work = abort_controller.raw_work.load(Ordering::Relaxed);
|
||||||
|
let deferred = abort_controller.raw_deferred.load(Ordering::Relaxed);
|
||||||
|
// abort function must be called from JavaScript main thread, so Relaxed Ordering is ok.
|
||||||
|
abort_controller.abort.store(true, Ordering::Relaxed);
|
||||||
|
napi_sys::napi_cancel_async_work(env, raw_async_work);
|
||||||
|
// napi_sys::napi_delete_async_work(env, raw_async_work);
|
||||||
|
let abort_error = Error::new(Status::Cancelled, "AbortError".to_owned());
|
||||||
|
let reject_status =
|
||||||
|
napi_sys::napi_reject_deferred(env, deferred, JsError::from(abort_error).into_value(env));
|
||||||
|
debug_assert_eq!(
|
||||||
|
reject_status,
|
||||||
|
napi_sys::Status::napi_ok,
|
||||||
|
"{}",
|
||||||
|
"Reject AbortError failed"
|
||||||
|
);
|
||||||
|
let mut undefined = ptr::null_mut();
|
||||||
|
napi_sys::napi_get_undefined(env, &mut undefined);
|
||||||
|
undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Task> ToNapiValue for AsyncTask<T> {
|
||||||
|
unsafe fn to_napi_value(
|
||||||
|
env: napi_sys::napi_env,
|
||||||
|
val: Self,
|
||||||
|
) -> crate::Result<napi_sys::napi_value> {
|
||||||
|
if let Some(abort_controller) = val.abort_controller {
|
||||||
|
let async_promise = async_work::run(env, val.inner, Some(abort_controller.abort.clone()))?;
|
||||||
|
abort_controller
|
||||||
|
.raw_work
|
||||||
|
.store(async_promise.napi_async_work, Ordering::Relaxed);
|
||||||
|
abort_controller
|
||||||
|
.raw_deferred
|
||||||
|
.store(async_promise.deferred, Ordering::Relaxed);
|
||||||
|
Ok(async_promise.promise_object().0.value)
|
||||||
|
} else {
|
||||||
|
let async_promise = async_work::run(env, val.inner, None)?;
|
||||||
|
Ok(async_promise.promise_object().0.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn async_task_abort_controller_finalize(
|
||||||
|
_env: napi_sys::napi_env,
|
||||||
|
finalize_data: *mut c_void,
|
||||||
|
_finalize_hint: *mut c_void,
|
||||||
|
) {
|
||||||
|
Box::from_raw(finalize_data as *mut AsyncTaskAbortController);
|
||||||
|
}
|
|
@ -485,7 +485,7 @@ impl Env {
|
||||||
#[cfg(feature = "napi5")]
|
#[cfg(feature = "napi5")]
|
||||||
pub fn create_function_from_closure<R, F>(&self, name: &str, callback: F) -> Result<JsFunction>
|
pub fn create_function_from_closure<R, F>(&self, name: &str, callback: F) -> Result<JsFunction>
|
||||||
where
|
where
|
||||||
F: 'static + Send + Sync + Fn(crate::CallContext<'_>) -> Result<R>,
|
F: 'static + Fn(crate::CallContext<'_>) -> Result<R>,
|
||||||
R: NapiRaw,
|
R: NapiRaw,
|
||||||
{
|
{
|
||||||
use crate::CallContext;
|
use crate::CallContext;
|
||||||
|
@ -925,7 +925,7 @@ impl Env {
|
||||||
|
|
||||||
/// Run [Task](./trait.Task.html) in libuv thread pool, return [AsyncWorkPromise](./struct.AsyncWorkPromise.html)
|
/// Run [Task](./trait.Task.html) in libuv thread pool, return [AsyncWorkPromise](./struct.AsyncWorkPromise.html)
|
||||||
pub fn spawn<T: 'static + Task>(&self, task: T) -> Result<AsyncWorkPromise> {
|
pub fn spawn<T: 'static + Task>(&self, task: T) -> Result<AsyncWorkPromise> {
|
||||||
async_work::run(self, task)
|
async_work::run(self.0, task, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_in_scope<T, F>(&self, executor: F) -> Result<T>
|
pub fn run_in_scope<T, F>(&self, executor: F) -> Result<T>
|
||||||
|
@ -1253,7 +1253,7 @@ unsafe extern "C" fn drop_buffer(
|
||||||
mem::drop(Vec::from_raw_parts(finalize_data as *mut u8, length, cap));
|
mem::drop(Vec::from_raw_parts(finalize_data as *mut u8, length, cap));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn raw_finalize<T>(
|
pub(crate) unsafe extern "C" fn raw_finalize<T>(
|
||||||
env: sys::napi_env,
|
env: sys::napi_env,
|
||||||
finalize_data: *mut c_void,
|
finalize_data: *mut c_void,
|
||||||
finalize_hint: *mut c_void,
|
finalize_hint: *mut c_void,
|
||||||
|
|
|
@ -3,10 +3,21 @@ use std::os::raw::c_void;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
|
use crate::bindgen_runtime::TypeName;
|
||||||
use crate::{check_status, sys, JsUnknown, NapiValue, Ref, Result, Value, ValueType};
|
use crate::{check_status, sys, JsUnknown, NapiValue, Ref, Result, Value, ValueType};
|
||||||
|
|
||||||
pub struct JsArrayBuffer(pub(crate) Value);
|
pub struct JsArrayBuffer(pub(crate) Value);
|
||||||
|
|
||||||
|
impl TypeName for JsArrayBuffer {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"ArrayBuffer"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> ValueType {
|
||||||
|
ValueType::Object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct JsArrayBufferValue {
|
pub struct JsArrayBufferValue {
|
||||||
pub(crate) value: JsArrayBuffer,
|
pub(crate) value: JsArrayBuffer,
|
||||||
len: usize,
|
len: usize,
|
||||||
|
@ -15,6 +26,16 @@ pub struct JsArrayBufferValue {
|
||||||
|
|
||||||
pub struct JsTypedArray(pub(crate) Value);
|
pub struct JsTypedArray(pub(crate) Value);
|
||||||
|
|
||||||
|
impl TypeName for JsTypedArray {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"TypedArray"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> ValueType {
|
||||||
|
ValueType::Object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct JsTypedArrayValue {
|
pub struct JsTypedArrayValue {
|
||||||
pub arraybuffer: JsArrayBuffer,
|
pub arraybuffer: JsArrayBuffer,
|
||||||
data: *mut c_void,
|
data: *mut c_void,
|
||||||
|
@ -25,6 +46,16 @@ pub struct JsTypedArrayValue {
|
||||||
|
|
||||||
pub struct JsDataView(pub(crate) Value);
|
pub struct JsDataView(pub(crate) Value);
|
||||||
|
|
||||||
|
impl TypeName for JsDataView {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"DataView"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> ValueType {
|
||||||
|
ValueType::Object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct JsDataViewValue {
|
pub struct JsDataViewValue {
|
||||||
pub arraybuffer: JsArrayBuffer,
|
pub arraybuffer: JsArrayBuffer,
|
||||||
_data: *mut c_void,
|
_data: *mut c_void,
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::convert::TryFrom;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{check_status, sys, Result};
|
use crate::{bindgen_runtime::TypeName, check_status, sys, Result};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct JsBigint {
|
pub struct JsBigint {
|
||||||
|
@ -10,6 +10,16 @@ pub struct JsBigint {
|
||||||
pub word_count: usize,
|
pub word_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TypeName for JsBigint {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"BigInt"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> ValueType {
|
||||||
|
ValueType::Bigint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl JsBigint {
|
impl JsBigint {
|
||||||
pub(crate) fn from_raw_unchecked(
|
pub(crate) fn from_raw_unchecked(
|
||||||
env: sys::napi_env,
|
env: sys::napi_env,
|
||||||
|
|
|
@ -1,12 +1,23 @@
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use super::Value;
|
use super::Value;
|
||||||
use crate::check_status;
|
use crate::bindgen_runtime::TypeName;
|
||||||
|
use crate::{check_status, ValueType};
|
||||||
use crate::{sys, Error, Result};
|
use crate::{sys, Error, Result};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct JsBoolean(pub(crate) Value);
|
pub struct JsBoolean(pub(crate) Value);
|
||||||
|
|
||||||
|
impl TypeName for JsBoolean {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"bool"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> crate::ValueType {
|
||||||
|
ValueType::Boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl JsBoolean {
|
impl JsBoolean {
|
||||||
pub fn get_value(&self) -> Result<bool> {
|
pub fn get_value(&self) -> Result<bool> {
|
||||||
let mut result = false;
|
let mut result = false;
|
||||||
|
|
|
@ -5,11 +5,22 @@ use std::ptr;
|
||||||
use super::Value;
|
use super::Value;
|
||||||
#[cfg(feature = "serde-json")]
|
#[cfg(feature = "serde-json")]
|
||||||
use super::ValueType;
|
use super::ValueType;
|
||||||
|
use crate::bindgen_runtime::TypeName;
|
||||||
use crate::check_status;
|
use crate::check_status;
|
||||||
use crate::{sys, JsUnknown, NapiValue, Ref, Result};
|
use crate::{sys, JsUnknown, NapiValue, Ref, Result};
|
||||||
|
|
||||||
pub struct JsBuffer(pub(crate) Value);
|
pub struct JsBuffer(pub(crate) Value);
|
||||||
|
|
||||||
|
impl TypeName for JsBuffer {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"Buffer"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> ValueType {
|
||||||
|
ValueType::Object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct JsBufferValue {
|
pub struct JsBufferValue {
|
||||||
pub(crate) value: JsBuffer,
|
pub(crate) value: JsBuffer,
|
||||||
data: mem::ManuallyDrop<Vec<u8>>,
|
data: mem::ManuallyDrop<Vec<u8>>,
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
use super::check_status;
|
use super::check_status;
|
||||||
use crate::{sys, Result, Value};
|
use crate::{bindgen_runtime::TypeName, sys, Result, Value, ValueType};
|
||||||
|
|
||||||
pub struct JsDate(pub(crate) Value);
|
pub struct JsDate(pub(crate) Value);
|
||||||
|
|
||||||
|
impl TypeName for JsDate {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"Date"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> crate::ValueType {
|
||||||
|
ValueType::Object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl JsDate {
|
impl JsDate {
|
||||||
pub fn value_of(&self) -> Result<f64> {
|
pub fn value_of(&self) -> Result<f64> {
|
||||||
let mut timestamp: f64 = 0.0;
|
let mut timestamp: f64 = 0.0;
|
||||||
|
|
|
@ -1,11 +1,22 @@
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use super::Value;
|
use super::Value;
|
||||||
use crate::check_status;
|
use crate::bindgen_runtime::TypeName;
|
||||||
|
use crate::{check_status, ValueType};
|
||||||
use crate::{sys, Env, Error, JsObject, JsUnknown, NapiRaw, NapiValue, Result, Status};
|
use crate::{sys, Env, Error, JsObject, JsUnknown, NapiRaw, NapiValue, Result, Status};
|
||||||
|
|
||||||
pub struct JsFunction(pub(crate) Value);
|
pub struct JsFunction(pub(crate) Value);
|
||||||
|
|
||||||
|
impl TypeName for JsFunction {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"Function"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> crate::ValueType {
|
||||||
|
ValueType::Function
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// See [Working with JavaScript Functions](https://nodejs.org/api/n-api.html#n_api_working_with_javascript_functions).
|
/// See [Working with JavaScript Functions](https://nodejs.org/api/n-api.html#n_api_working_with_javascript_functions).
|
||||||
///
|
///
|
||||||
/// Example:
|
/// Example:
|
||||||
|
|
|
@ -2,7 +2,9 @@ use std::convert::TryFrom;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use crate::{check_status, sys, type_of, Callback, Error, Result, Status, ValueType};
|
use crate::{
|
||||||
|
bindgen_runtime::TypeName, check_status, sys, type_of, Callback, Error, Result, Status, ValueType,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(feature = "serde-json")]
|
#[cfg(feature = "serde-json")]
|
||||||
mod de;
|
mod de;
|
||||||
|
@ -60,11 +62,41 @@ pub struct JsUnknown(pub(crate) Value);
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct JsNull(pub(crate) Value);
|
pub struct JsNull(pub(crate) Value);
|
||||||
|
|
||||||
|
impl TypeName for JsNull {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"null"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> ValueType {
|
||||||
|
ValueType::Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct JsSymbol(pub(crate) Value);
|
pub struct JsSymbol(pub(crate) Value);
|
||||||
|
|
||||||
|
impl TypeName for JsSymbol {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"symbol"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> ValueType {
|
||||||
|
ValueType::Symbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct JsExternal(pub(crate) Value);
|
pub struct JsExternal(pub(crate) Value);
|
||||||
|
|
||||||
|
impl TypeName for JsExternal {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"external"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> ValueType {
|
||||||
|
ValueType::External
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! impl_napi_value_trait {
|
macro_rules! impl_napi_value_trait {
|
||||||
($js_value:ident, $value_type:ident) => {
|
($js_value:ident, $value_type:ident) => {
|
||||||
impl NapiValue for $js_value {
|
impl NapiValue for $js_value {
|
||||||
|
|
|
@ -1,12 +1,23 @@
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use super::Value;
|
use super::Value;
|
||||||
use crate::check_status;
|
use crate::bindgen_runtime::TypeName;
|
||||||
|
use crate::{check_status, ValueType};
|
||||||
use crate::{sys, Error, Result};
|
use crate::{sys, Error, Result};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct JsNumber(pub(crate) Value);
|
pub struct JsNumber(pub(crate) Value);
|
||||||
|
|
||||||
|
impl TypeName for JsNumber {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"f64"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> crate::ValueType {
|
||||||
|
ValueType::Number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl JsNumber {
|
impl JsNumber {
|
||||||
pub fn get_uint32(&self) -> Result<u32> {
|
pub fn get_uint32(&self) -> Result<u32> {
|
||||||
let mut result = 0;
|
let mut result = 0;
|
||||||
|
|
|
@ -8,6 +8,7 @@ use std::ptr;
|
||||||
#[cfg(feature = "napi5")]
|
#[cfg(feature = "napi5")]
|
||||||
use super::check_status;
|
use super::check_status;
|
||||||
use super::Value;
|
use super::Value;
|
||||||
|
use crate::bindgen_runtime::TypeName;
|
||||||
#[cfg(feature = "napi5")]
|
#[cfg(feature = "napi5")]
|
||||||
use crate::sys;
|
use crate::sys;
|
||||||
#[cfg(feature = "napi5")]
|
#[cfg(feature = "napi5")]
|
||||||
|
@ -16,9 +17,20 @@ use crate::Env;
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
#[cfg(feature = "napi5")]
|
#[cfg(feature = "napi5")]
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
use crate::ValueType;
|
||||||
|
|
||||||
pub struct JsObject(pub(crate) Value);
|
pub struct JsObject(pub(crate) Value);
|
||||||
|
|
||||||
|
impl TypeName for JsObject {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"Object"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> crate::ValueType {
|
||||||
|
ValueType::Object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "napi5")]
|
#[cfg(feature = "napi5")]
|
||||||
pub struct FinalizeContext<T: 'static, Hint: 'static> {
|
pub struct FinalizeContext<T: 'static, Hint: 'static> {
|
||||||
pub env: Env,
|
pub env: Env,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
use crate::bindgen_runtime::TypeName;
|
||||||
|
use crate::ValueType;
|
||||||
use crate::{check_status, sys, Result, Value};
|
use crate::{check_status, sys, Result, Value};
|
||||||
|
|
||||||
pub use latin1::JsStringLatin1;
|
pub use latin1::JsStringLatin1;
|
||||||
|
@ -14,6 +16,16 @@ mod utf8;
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct JsString(pub(crate) Value);
|
pub struct JsString(pub(crate) Value);
|
||||||
|
|
||||||
|
impl TypeName for JsString {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"String"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> crate::ValueType {
|
||||||
|
ValueType::String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl JsString {
|
impl JsString {
|
||||||
pub fn utf8_len(&self) -> Result<usize> {
|
pub fn utf8_len(&self) -> Result<usize> {
|
||||||
let mut length = 0;
|
let mut length = 0;
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
|
use crate::{bindgen_runtime::TypeName, ValueType};
|
||||||
|
|
||||||
use super::Value;
|
use super::Value;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct JsUndefined(pub(crate) Value);
|
pub struct JsUndefined(pub(crate) Value);
|
||||||
|
|
||||||
|
impl TypeName for JsUndefined {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_type() -> crate::ValueType {
|
||||||
|
ValueType::Undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
use crate::{js_values::NapiValue, Env, Error, Result};
|
use crate::{
|
||||||
|
bindgen_runtime::{ToNapiValue, TypeName},
|
||||||
|
Env, Error, Result,
|
||||||
|
};
|
||||||
|
|
||||||
pub trait Task: Send + Sized {
|
pub trait Task: Send + Sized {
|
||||||
type Output: Send + Sized + 'static;
|
type Output: Send + Sized + 'static;
|
||||||
type JsValue: NapiValue;
|
type JsValue: ToNapiValue + TypeName;
|
||||||
|
|
||||||
/// Compute logic in libuv thread
|
/// Compute logic in libuv thread
|
||||||
fn compute(&mut self) -> Result<Self::Output>;
|
fn compute(&mut self) -> Result<Self::Output>;
|
||||||
|
@ -14,4 +17,7 @@ pub trait Task: Send + Sized {
|
||||||
fn reject(self, _env: Env, err: Error) -> Result<Self::JsValue> {
|
fn reject(self, _env: Env, err: Error) -> Result<Self::JsValue> {
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// after resolve or reject
|
||||||
|
fn finally() {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,8 @@ Generated by [AVA](https://avajs.dev).
|
||||||
export function concatStr(mutS: string): string␊
|
export function concatStr(mutS: string): string␊
|
||||||
export function concatUtf16(s: string): string␊
|
export function concatUtf16(s: string): string␊
|
||||||
export function concatLatin1(s: string): string␊
|
export function concatLatin1(s: string): string␊
|
||||||
|
export function withoutAbortController(a: number, b: number): Promise<number>␊
|
||||||
|
export function withAbortController(a: number, b: number, ctrl: AbortController): Promise<number>␊
|
||||||
export function getBuffer(): Buffer␊
|
export function getBuffer(): Buffer␊
|
||||||
export class Animal {␊
|
export class Animal {␊
|
||||||
readonly kind: Kind␊
|
readonly kind: Kind␊
|
||||||
|
|
Binary file not shown.
|
@ -30,6 +30,8 @@ import {
|
||||||
returnEither,
|
returnEither,
|
||||||
either3,
|
either3,
|
||||||
either4,
|
either4,
|
||||||
|
withoutAbortController,
|
||||||
|
withAbortController,
|
||||||
} from '../'
|
} from '../'
|
||||||
|
|
||||||
test('number', (t) => {
|
test('number', (t) => {
|
||||||
|
@ -160,3 +162,19 @@ test('either4', (t) => {
|
||||||
t.is(either4({ v: 1 }), 1)
|
t.is(either4({ v: 1 }), 1)
|
||||||
t.is(either4({ v: 'world' }), 'world'.length)
|
t.is(either4({ v: 'world' }), 'world'.length)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('async task without abort controller', async (t) => {
|
||||||
|
t.is(await withoutAbortController(1, 2), 3)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('async task with abort controller', async (t) => {
|
||||||
|
const ctrl = new AbortController()
|
||||||
|
const promise = withAbortController(1, 2, ctrl)
|
||||||
|
try {
|
||||||
|
ctrl.abort()
|
||||||
|
await promise
|
||||||
|
t.fail('Should throw AbortError')
|
||||||
|
} catch (err: unknown) {
|
||||||
|
t.is((err as Error).message, 'AbortError')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
2
examples/napi/index.d.ts
vendored
2
examples/napi/index.d.ts
vendored
|
@ -32,6 +32,8 @@ export function contains(source: string, target: string): boolean
|
||||||
export function concatStr(mutS: string): string
|
export function concatStr(mutS: string): string
|
||||||
export function concatUtf16(s: string): string
|
export function concatUtf16(s: string): string
|
||||||
export function concatLatin1(s: string): string
|
export function concatLatin1(s: string): string
|
||||||
|
export function withoutAbortController(a: number, b: number): Promise<number>
|
||||||
|
export function withAbortController(a: number, b: number, ctrl: AbortController): Promise<number>
|
||||||
export function getBuffer(): Buffer
|
export function getBuffer(): Buffer
|
||||||
export class Animal {
|
export class Animal {
|
||||||
readonly kind: Kind
|
readonly kind: Kind
|
||||||
|
|
|
@ -15,4 +15,5 @@ mod number;
|
||||||
mod object;
|
mod object;
|
||||||
mod serde;
|
mod serde;
|
||||||
mod string;
|
mod string;
|
||||||
|
mod task;
|
||||||
mod typed_array;
|
mod typed_array;
|
||||||
|
|
31
examples/napi/src/task.rs
Normal file
31
examples/napi/src/task.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
use std::thread::sleep;
|
||||||
|
|
||||||
|
use napi::bindgen_prelude::*;
|
||||||
|
use napi::Task;
|
||||||
|
|
||||||
|
struct DelaySum(u32, u32);
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
impl Task for DelaySum {
|
||||||
|
type Output = u32;
|
||||||
|
type JsValue = u32;
|
||||||
|
|
||||||
|
fn compute(&mut self) -> Result<Self::Output> {
|
||||||
|
sleep(std::time::Duration::from_secs(1));
|
||||||
|
Ok(self.0 + self.1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve(self, _env: napi::Env, output: Self::Output) -> Result<Self::JsValue> {
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
fn without_abort_controller(a: u32, b: u32) -> AsyncTask<DelaySum> {
|
||||||
|
AsyncTask::new(DelaySum(a, b))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
fn with_abort_controller(a: u32, b: u32, ctrl: AsyncTaskAbortController) -> AsyncTask<DelaySum> {
|
||||||
|
AsyncTask::with_abort_controller(DelaySum(a, b), ctrl)
|
||||||
|
}
|
Loading…
Reference in a new issue