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