Struct napi::bindgen_prelude::JsError
source · pub struct JsError(_);
Implementations§
source§impl JsError
impl JsError
sourcepub unsafe fn into_value(self, env: napi_env) -> napi_value
pub unsafe fn into_value(self, env: napi_env) -> napi_value
Safety
This function is safety if env is not null ptr.
Examples found in repository?
More examples
src/error.rs (line 35)
33 34 35 36 37 38 39 40 41 42 43 44
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
if val.maybe_raw.is_null() {
let err = unsafe { JsError::from(val).into_value(env) };
Ok(err)
} else {
let mut value = std::ptr::null_mut();
check_status!(unsafe {
sys::napi_get_reference_value(val.maybe_env, val.maybe_raw, &mut value)
})?;
Ok(value)
}
}
src/js_values/deferred.rs (line 122)
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
extern "C" fn napi_resolve_deferred<Data: ToNapiValue, Resolver: FnOnce(Env) -> Result<Data>>(
env: sys::napi_env,
_js_callback: sys::napi_value,
context: *mut c_void,
data: *mut c_void,
) {
let deferred = context as sys::napi_deferred;
let resolver = unsafe { Box::from_raw(data as *mut Result<Resolver>) };
let result = resolver
.and_then(|resolver| resolver(unsafe { Env::from_raw(env) }))
.and_then(|res| unsafe { ToNapiValue::to_napi_value(env, res) });
match result {
Ok(res) => {
let status = unsafe { sys::napi_resolve_deferred(env, deferred, res) };
debug_assert!(status == sys::Status::napi_ok, "Resolve promise failed");
}
Err(e) => {
let status =
unsafe { sys::napi_reject_deferred(env, deferred, JsError::from(e).into_value(env)) };
debug_assert!(status == sys::Status::napi_ok, "Reject promise failed");
}
}
}
src/bindgen_runtime/js_values/task.rs (line 128)
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
extern "C" fn on_abort(
env: sys::napi_env,
callback_info: sys::napi_callback_info,
) -> sys::napi_value {
let mut this = ptr::null_mut();
unsafe {
let get_cb_info_status = 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,
sys::Status::napi_ok,
"{}",
"Get callback info in AbortController abort callback failed"
);
let mut async_task = ptr::null_mut();
let status = sys::napi_unwrap(env, this, &mut async_task);
debug_assert_eq!(
status,
sys::Status::napi_ok,
"{}",
"Unwrap async_task from AbortSignal failed"
);
let abort_controller = Box::leak(Box::from_raw(async_task as *mut AbortSignal));
// Task Completed, return now
if abort_controller.status.load(Ordering::Relaxed) == 1 {
return ptr::null_mut();
}
let raw_async_work = abort_controller.raw_work.load(Ordering::Relaxed);
let deferred = abort_controller.raw_deferred.load(Ordering::Relaxed);
sys::napi_cancel_async_work(env, raw_async_work);
// abort function must be called from JavaScript main thread, so Relaxed Ordering is ok.
abort_controller.status.store(2, Ordering::Relaxed);
let abort_error = Error::new(Status::Cancelled, "AbortError".to_owned());
let reject_status =
sys::napi_reject_deferred(env, deferred, JsError::from(abort_error).into_value(env));
debug_assert_eq!(
reject_status,
sys::Status::napi_ok,
"{}",
"Reject AbortError failed"
);
}
ptr::null_mut()
}
src/async_work.rs (line 139)
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
unsafe extern "C" fn complete<T: Task>(
env: sys::napi_env,
status: sys::napi_status,
data: *mut c_void,
) {
let mut work = unsafe { Box::from_raw(data as *mut AsyncWork<T>) };
let value_ptr = mem::replace(&mut work.value, Ok(mem::MaybeUninit::zeroed()));
let deferred = mem::replace(&mut work.deferred, ptr::null_mut());
let napi_async_work = mem::replace(&mut work.napi_async_work, ptr::null_mut());
let value = match value_ptr {
Ok(v) => {
let output = unsafe { v.assume_init() };
work
.inner_task
.resolve(unsafe { Env::from_raw(env) }, output)
}
Err(e) => work.inner_task.reject(unsafe { Env::from_raw(env) }, e),
};
if status != sys::Status::napi_cancelled && work.status.load(Ordering::Relaxed) != 2 {
match check_status!(status)
.and_then(move |_| value)
.and_then(|v| unsafe { ToNapiValue::to_napi_value(env, v) })
{
Ok(v) => {
let status = unsafe { sys::napi_resolve_deferred(env, deferred, v) };
debug_assert!(status == sys::Status::napi_ok, "Resolve promise failed");
}
Err(e) => {
let status =
unsafe { sys::napi_reject_deferred(env, deferred, JsError::from(e).into_value(env)) };
debug_assert!(status == sys::Status::napi_ok, "Reject promise failed");
}
};
}
if let Err(e) = work.inner_task.finally(unsafe { Env::from_raw(env) }) {
debug_assert!(false, "Panic in Task finally fn: {:?}", e);
}
let delete_status = unsafe { sys::napi_delete_async_work(env, napi_async_work) };
debug_assert!(
delete_status == sys::Status::napi_ok,
"Delete async work failed"
);
work.status.store(1, Ordering::Relaxed);
}
src/threadsafe_function.rs (line 424)
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
unsafe extern "C" fn call_js_cb<T: 'static, V: ToNapiValue, R, ES>(
raw_env: sys::napi_env,
js_callback: sys::napi_value,
context: *mut c_void,
data: *mut c_void,
) where
R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
ES: ErrorStrategy::T,
{
// env and/or callback can be null when shutting down
if raw_env.is_null() || js_callback.is_null() {
return;
}
let ctx: &mut R = unsafe { &mut *context.cast::<R>() };
let val: Result<T> = unsafe {
match ES::VALUE {
ErrorStrategy::CalleeHandled::VALUE => *Box::<Result<T>>::from_raw(data.cast()),
ErrorStrategy::Fatal::VALUE => Ok(*Box::<T>::from_raw(data.cast())),
}
};
let mut recv = ptr::null_mut();
unsafe { sys::napi_get_undefined(raw_env, &mut recv) };
let ret = val.and_then(|v| {
(ctx)(ThreadSafeCallContext {
env: unsafe { Env::from_raw(raw_env) },
value: v,
})
});
// Follow async callback conventions: https://nodejs.org/en/knowledge/errors/what-are-the-error-conventions/
// Check if the Result is okay, if so, pass a null as the first (error) argument automatically.
// If the Result is an error, pass that as the first argument.
let status = match ret {
Ok(values) => {
let values = values
.into_iter()
.map(|v| unsafe { ToNapiValue::to_napi_value(raw_env, v) });
let args: Result<Vec<sys::napi_value>> = if ES::VALUE == ErrorStrategy::CalleeHandled::VALUE {
let mut js_null = ptr::null_mut();
unsafe { sys::napi_get_null(raw_env, &mut js_null) };
::core::iter::once(Ok(js_null)).chain(values).collect()
} else {
values.collect()
};
match args {
Ok(args) => unsafe {
sys::napi_call_function(
raw_env,
recv,
js_callback,
args.len(),
args.as_ptr(),
ptr::null_mut(),
)
},
Err(e) => match ES::VALUE {
ErrorStrategy::Fatal::VALUE => unsafe {
sys::napi_fatal_exception(raw_env, JsError::from(e).into_value(raw_env))
},
ErrorStrategy::CalleeHandled::VALUE => unsafe {
sys::napi_call_function(
raw_env,
recv,
js_callback,
1,
[JsError::from(e).into_value(raw_env)].as_mut_ptr(),
ptr::null_mut(),
)
},
},
}
}
Err(e) if ES::VALUE == ErrorStrategy::Fatal::VALUE => unsafe {
sys::napi_fatal_exception(raw_env, JsError::from(e).into_value(raw_env))
},
Err(e) => unsafe {
sys::napi_call_function(
raw_env,
recv,
js_callback,
1,
[JsError::from(e).into_value(raw_env)].as_mut_ptr(),
ptr::null_mut(),
)
},
};
if status == sys::Status::napi_ok {
return;
}
if status == sys::Status::napi_pending_exception {
let mut error_result = ptr::null_mut();
assert_eq!(
unsafe { sys::napi_get_and_clear_last_exception(raw_env, &mut error_result) },
sys::Status::napi_ok
);
// When shutting down, napi_fatal_exception sometimes returns another exception
let stat = unsafe { sys::napi_fatal_exception(raw_env, error_result) };
assert!(stat == sys::Status::napi_ok || stat == sys::Status::napi_pending_exception);
} else {
let error_code: Status = status.into();
let error_code_string = format!("{:?}", error_code);
let mut error_code_value = ptr::null_mut();
assert_eq!(
unsafe {
sys::napi_create_string_utf8(
raw_env,
error_code_string.as_ptr() as *const _,
error_code_string.len(),
&mut error_code_value,
)
},
sys::Status::napi_ok,
);
let error_msg = "Call JavaScript callback failed in thread safe function";
let mut error_msg_value = ptr::null_mut();
assert_eq!(
unsafe {
sys::napi_create_string_utf8(
raw_env,
error_msg.as_ptr() as *const _,
error_msg.len(),
&mut error_msg_value,
)
},
sys::Status::napi_ok,
);
let mut error_value = ptr::null_mut();
assert_eq!(
unsafe {
sys::napi_create_error(raw_env, error_code_value, error_msg_value, &mut error_value)
},
sys::Status::napi_ok,
);
assert_eq!(
unsafe { sys::napi_fatal_exception(raw_env, error_value) },
sys::Status::napi_ok
);
}
}
pub fn into_unknown(self, env: Env) -> JsUnknown
sourcepub unsafe fn throw_into(self, env: napi_env)
pub unsafe fn throw_into(self, env: napi_env)
Safety
This function is safety if env is not null ptr.
Examples found in repository?
src/bindgen_runtime/mod.rs (line 40)
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
pub unsafe extern "C" fn raw_finalize_unchecked<T: ObjectFinalize>(
env: sys::napi_env,
finalize_data: *mut c_void,
_finalize_hint: *mut c_void,
) {
let data = *unsafe { Box::from_raw(finalize_data as *mut T) };
if let Err(err) = data.finalize(unsafe { Env::from_raw(env) }) {
let e: JsError = err.into();
unsafe { e.throw_into(env) };
}
if let Some((_, ref_val, finalize_callbacks_ptr)) =
REFERENCE_MAP.borrow_mut(|reference_map| reference_map.remove(&finalize_data))
{
let finalize_callbacks_rc = unsafe { Rc::from_raw(finalize_callbacks_ptr) };
#[cfg(debug_assertions)]
{
let rc_strong_count = Rc::strong_count(&finalize_callbacks_rc);
// If `Rc` strong count is 2, it means the finalize of referenced `Object` is called before the `fn drop` of the `Reference`
// It always happened on exiting process
// In general, the `fn drop` would happen first
assert!(
rc_strong_count == 1 || rc_strong_count == 2,
"Rc strong count is: {}, it should be 1 or 2",
rc_strong_count
);
}
let finalize = unsafe { Box::from_raw(finalize_callbacks_rc.get()) };
finalize();
let delete_reference_status = unsafe { sys::napi_delete_reference(env, ref_val) };
debug_assert!(
delete_reference_status == sys::Status::napi_ok,
"Delete reference in finalize callback failed {}",
Status::from(delete_reference_status)
);
}
}
More examples
src/env.rs (line 597)
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
unsafe extern "C" fn trampoline<R: NapiRaw, F: Fn(CallContext<'_>) -> Result<R>>(
raw_env: sys::napi_env,
cb_info: sys::napi_callback_info,
) -> sys::napi_value {
use ::std::panic::{self, AssertUnwindSafe};
panic::catch_unwind(AssertUnwindSafe(|| {
let (raw_this, ref raw_args, closure_data_ptr) = {
let argc = {
let mut argc = 0;
let status = unsafe {
sys::napi_get_cb_info(
raw_env,
cb_info,
&mut argc,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
)
};
debug_assert!(
Status::from(status) == Status::Ok,
"napi_get_cb_info failed"
);
argc
};
let mut raw_args = vec![ptr::null_mut(); argc];
let mut raw_this = ptr::null_mut();
let mut closure_data_ptr = ptr::null_mut();
let status = unsafe {
sys::napi_get_cb_info(
raw_env,
cb_info,
&mut { argc },
raw_args.as_mut_ptr(),
&mut raw_this,
&mut closure_data_ptr,
)
};
debug_assert!(
Status::from(status) == Status::Ok,
"napi_get_cb_info failed"
);
(raw_this, raw_args, closure_data_ptr)
};
let closure: &F = unsafe {
closure_data_ptr
.cast::<F>()
.as_ref()
.expect("`napi_get_cb_info` should have yielded non-`NULL` assoc data")
};
let env = &mut unsafe { Env::from_raw(raw_env) };
let ctx = CallContext::new(env, cb_info, raw_this, raw_args, raw_args.len());
closure(ctx).map(|ret: R| unsafe { ret.raw() })
}))
.map_err(|e| {
Error::from_reason(format!(
"panic from Rust code: {}",
if let Some(s) = e.downcast_ref::<String>() {
s
} else if let Some(s) = e.downcast_ref::<&str>() {
s
} else {
"<no error message>"
},
))
})
.and_then(|v| v)
.unwrap_or_else(|e| {
unsafe { JsError::from(e).throw_into(raw_env) };
ptr::null_mut()
})
}
src/bindgen_runtime/module_register.rs (line 370)
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
unsafe extern "C" fn napi_register_module_v1(
env: sys::napi_env,
exports: sys::napi_value,
) -> sys::napi_value {
if IS_FIRST_MODULE.load(Ordering::SeqCst) {
IS_FIRST_MODULE.store(false, Ordering::SeqCst);
} else {
wait_first_thread_registered();
}
crate::__private::___CALL_FROM_FACTORY.get_or_default();
let mut exports_objects: HashSet<String> = HashSet::default();
MODULE_REGISTER_CALLBACK.borrow_mut(|inner| {
inner
.iter_mut()
.fold(
HashMap::<Option<&'static str>, Vec<(&'static str, ExportRegisterCallback)>>::new(),
|mut acc, (js_mod, item)| {
if let Some(k) = acc.get_mut(js_mod) {
k.push(*item);
} else {
acc.insert(*js_mod, vec![*item]);
}
acc
},
)
.iter()
.for_each(|(js_mod, items)| {
let mut exports_js_mod = ptr::null_mut();
if let Some(js_mod_str) = js_mod {
let mod_name_c_str =
unsafe { CStr::from_bytes_with_nul_unchecked(js_mod_str.as_bytes()) };
if exports_objects.contains(*js_mod_str) {
check_status_or_throw!(
env,
unsafe {
sys::napi_get_named_property(
env,
exports,
mod_name_c_str.as_ptr(),
&mut exports_js_mod,
)
},
"Get mod {} from exports failed",
js_mod_str,
);
} else {
check_status_or_throw!(
env,
unsafe { sys::napi_create_object(env, &mut exports_js_mod) },
"Create export JavaScript Object [{}] failed",
js_mod_str
);
check_status_or_throw!(
env,
unsafe {
sys::napi_set_named_property(env, exports, mod_name_c_str.as_ptr(), exports_js_mod)
},
"Set exports Object [{}] into exports object failed",
js_mod_str
);
exports_objects.insert(js_mod_str.to_string());
}
}
for (name, callback) in items {
unsafe {
let js_name = CStr::from_bytes_with_nul_unchecked(name.as_bytes());
if let Err(e) = callback(env).and_then(|v| {
let exported_object = if exports_js_mod.is_null() {
exports
} else {
exports_js_mod
};
check_status!(
sys::napi_set_named_property(env, exported_object, js_name.as_ptr(), v),
"Failed to register export `{}`",
name,
)
}) {
JsError::from(e).throw_into(env)
}
}
}
})
});
let mut registered_classes = HashMap::new();
MODULE_CLASS_PROPERTIES.borrow_mut(|inner| {
inner.iter().for_each(|(rust_name, js_mods)| {
for (js_mod, (js_name, props)) in js_mods {
let mut exports_js_mod = ptr::null_mut();
unsafe {
if let Some(js_mod_str) = js_mod {
let mod_name_c_str = CStr::from_bytes_with_nul_unchecked(js_mod_str.as_bytes());
if exports_objects.contains(*js_mod_str) {
check_status_or_throw!(
env,
sys::napi_get_named_property(
env,
exports,
mod_name_c_str.as_ptr(),
&mut exports_js_mod,
),
"Get mod {} from exports failed",
js_mod_str,
);
} else {
check_status_or_throw!(
env,
sys::napi_create_object(env, &mut exports_js_mod),
"Create export JavaScript Object [{}] failed",
js_mod_str
);
check_status_or_throw!(
env,
sys::napi_set_named_property(env, exports, mod_name_c_str.as_ptr(), exports_js_mod),
"Set exports Object [{}] into exports object failed",
js_mod_str
);
exports_objects.insert(js_mod_str.to_string());
}
}
let (ctor, props): (Vec<_>, Vec<_>) = props.iter().partition(|prop| prop.is_ctor);
let ctor = ctor.get(0).map(|c| c.raw().method.unwrap()).unwrap_or(noop);
let raw_props: Vec<_> = props.iter().map(|prop| prop.raw()).collect();
let js_class_name = CStr::from_bytes_with_nul_unchecked(js_name.as_bytes());
let mut class_ptr = ptr::null_mut();
check_status_or_throw!(
env,
sys::napi_define_class(
env,
js_class_name.as_ptr(),
js_name.len() - 1,
Some(ctor),
ptr::null_mut(),
raw_props.len(),
raw_props.as_ptr(),
&mut class_ptr,
),
"Failed to register class `{}` generate by struct `{}`",
&js_name,
&rust_name
);
let mut ctor_ref = ptr::null_mut();
sys::napi_create_reference(env, class_ptr, 1, &mut ctor_ref);
registered_classes.insert(js_name.to_string(), ctor_ref);
check_status_or_throw!(
env,
sys::napi_set_named_property(
env,
if exports_js_mod.is_null() {
exports
} else {
exports_js_mod
},
js_class_name.as_ptr(),
class_ptr
),
"Failed to register class `{}` generate by struct `{}`",
&js_name,
&rust_name
);
}
}
});
REGISTERED_CLASSES.borrow_mut(|map| {
map.insert(
std::thread::current().id(),
PersistedPerInstanceHashMap::from_hashmap(registered_classes),
)
});
});
#[cfg(feature = "compat-mode")]
MODULE_EXPORTS.borrow_mut(|inner| {
inner.iter().for_each(|callback| unsafe {
if let Err(e) = callback(env, exports) {
JsError::from(e).throw_into(env);
}
})
});
#[cfg(all(windows, feature = "napi4", feature = "tokio_rt"))]
{
crate::tokio_runtime::RT_REFERENCE_COUNT.fetch_add(1, Ordering::SeqCst);
unsafe {
sys::napi_add_env_cleanup_hook(
env,
Some(crate::tokio_runtime::drop_runtime),
ptr::null_mut(),
)
};
}
#[cfg(feature = "napi4")]
create_custom_gc(env);
FIRST_MODULE_REGISTERED.store(true, Ordering::SeqCst);
exports
}
pub fn throw(&self, env: napi_env) -> Result<()>
Trait Implementations§
source§impl ToNapiValue for JsError
impl ToNapiValue for JsError
source§unsafe fn to_napi_value(env: napi_env, val: Self) -> Result<napi_value>
unsafe fn to_napi_value(env: napi_env, val: Self) -> Result<napi_value>
Safety Read more