1use std::panic::{catch_unwind, UnwindSafe};
4
5use crate::{
6 context::{
7 internal::{ContextInternal, Env},
8 Context, Cx,
9 },
10 handle::{internal::TransparentNoCopyWrapper, Handle},
11 object::Object,
12 result::{NeonResult, Throw},
13 sys::{self, raw},
14 types::{build, private::ValueInternal, utf8::Utf8, Value},
15};
16
17#[repr(transparent)]
39#[derive(Debug)]
40pub struct JsError(raw::Local);
41
42unsafe impl TransparentNoCopyWrapper for JsError {
43 type Inner = raw::Local;
44
45 fn into_inner(self) -> Self::Inner {
46 self.0
47 }
48}
49
50impl ValueInternal for JsError {
51 fn name() -> &'static str {
52 "Error"
53 }
54
55 fn is_typeof<Other: Value>(cx: &mut Cx, other: &Other) -> bool {
56 unsafe { sys::tag::is_error(cx.env().to_raw(), other.to_local()) }
57 }
58
59 fn to_local(&self) -> raw::Local {
60 self.0
61 }
62
63 unsafe fn from_local(_env: Env, h: raw::Local) -> Self {
64 JsError(h)
65 }
66}
67
68impl Value for JsError {}
69
70impl Object for JsError {}
71
72impl JsError {
73 pub fn error<'a, C: Context<'a>, S: AsRef<str>>(
77 cx: &mut C,
78 msg: S,
79 ) -> NeonResult<Handle<'a, JsError>> {
80 let msg = cx.string(msg.as_ref());
81 build(cx.env(), |out| unsafe {
82 sys::error::new_error(cx.env().to_raw(), out, msg.to_local());
83 true
84 })
85 }
86
87 pub fn type_error<'a, C: Context<'a>, S: AsRef<str>>(
91 cx: &mut C,
92 msg: S,
93 ) -> NeonResult<Handle<'a, JsError>> {
94 let msg = cx.string(msg.as_ref());
95 build(cx.env(), |out| unsafe {
96 sys::error::new_type_error(cx.env().to_raw(), out, msg.to_local());
97 true
98 })
99 }
100
101 pub fn range_error<'a, C: Context<'a>, S: AsRef<str>>(
105 cx: &mut C,
106 msg: S,
107 ) -> NeonResult<Handle<'a, JsError>> {
108 let msg = cx.string(msg.as_ref());
109 build(cx.env(), |out| unsafe {
110 sys::error::new_range_error(cx.env().to_raw(), out, msg.to_local());
111 true
112 })
113 }
114}
115
116pub(crate) fn convert_panics<T, F: UnwindSafe + FnOnce() -> NeonResult<T>>(
117 env: Env,
118 f: F,
119) -> NeonResult<T> {
120 match catch_unwind(f) {
121 Ok(result) => result,
122 Err(panic) => {
123 let msg = if let Some(string) = panic.downcast_ref::<String>() {
124 format!("internal error in Neon module: {string}")
125 } else if let Some(str) = panic.downcast_ref::<&str>() {
126 format!("internal error in Neon module: {str}")
127 } else {
128 "internal error in Neon module".to_string()
129 };
130 let (data, len) = Utf8::from(&msg[..]).truncate().lower();
131 unsafe {
132 sys::error::clear_exception(env.to_raw());
133 sys::error::throw_error_from_utf8(env.to_raw(), data, len);
134 Err(Throw::new())
135 }
136 }
137 }
138}