1use alloc::boxed::Box;
2use alloc::string::{String, ToString as _};
3use core::{error, fmt};
4
5use rquickjs::{Ctx, Error as JSError, Exception, Value};
6use serde::{de, ser};
7
8pub struct Error(Box<ErrorImpl>);
11
12impl Error {
13 pub(crate) fn new(msg: impl Into<ErrorImpl>) -> Self {
14 Error(Box::new(msg.into()))
15 }
16
17 pub fn catch<'js>(self, ctx: &Ctx<'js>) -> CaughtError<'js> {
18 self.0.catch(ctx)
19 }
20}
21
22pub type Result<T> = core::result::Result<T, Error>;
24
25impl fmt::Debug for Error {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 write!(f, "Error({})", self.0)
28 }
29}
30
31impl error::Error for Error {}
32
33impl fmt::Display for Error {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 fmt::Display::fmt(&*self.0, f)
36 }
37}
38
39impl de::Error for Error {
40 fn custom<T: fmt::Display>(msg: T) -> Self {
41 Error(Box::new(ErrorImpl::Message(msg.to_string())))
42 }
43}
44
45impl ser::Error for Error {
46 fn custom<T: fmt::Display>(msg: T) -> Self {
47 Error(Box::new(ErrorImpl::Message(msg.to_string())))
48 }
49}
50
51#[derive(Debug)]
56pub enum ErrorImpl {
57 Message(String),
59 Rquickjs(JSError),
61}
62
63impl ErrorImpl {
64 pub fn catch<'js>(self, ctx: &Ctx<'js>) -> CaughtError<'js> {
65 match self {
66 ErrorImpl::Message(msg) => CaughtError::Message(msg),
67 ErrorImpl::Rquickjs(JSError::Exception) => {
68 let value = ctx.catch();
69 if let Some(ex) = value
70 .as_object()
71 .and_then(|x| Exception::from_object(x.clone()))
72 {
73 CaughtError::Exception(ex)
74 } else {
75 CaughtError::Value(value)
76 }
77 }
78 ErrorImpl::Rquickjs(e) => CaughtError::Error(e),
79 }
80 }
81}
82
83impl fmt::Display for ErrorImpl {
84 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85 match self {
86 ErrorImpl::Message(msg) => write!(f, "{msg}"),
87 ErrorImpl::Rquickjs(e) => write!(f, "JSError: {e}"),
90 }
91 }
92}
93
94impl From<&str> for ErrorImpl {
95 fn from(value: &str) -> Self {
96 ErrorImpl::Message(value.to_string())
97 }
98}
99
100impl From<JSError> for ErrorImpl {
101 fn from(value: JSError) -> Self {
102 ErrorImpl::Rquickjs(value)
103 }
104}
105
106#[derive(Debug)]
108pub enum CaughtError<'js> {
109 Exception(Exception<'js>),
111 Value(Value<'js>),
113 Error(JSError),
115 Message(String),
117}
118
119impl<'js> fmt::Display for CaughtError<'js> {
120 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121 match self {
122 CaughtError::Error(e) => e.fmt(f),
123 CaughtError::Exception(e) => e.fmt(f),
124 CaughtError::Value(e) => {
125 writeln!(f, "Exception generated by quickjs: {e:?}")
126 }
127 CaughtError::Message(msg) => write!(f, "{msg}"),
128 }
129 }
130}
131
132impl<'js> error::Error for CaughtError<'js> {}