rquickjs_serde/
err.rs

1use std::{error, fmt};
2
3use rquickjs::{Ctx, Error as JSError, Exception, Value};
4use serde::{de, ser};
5
6/// This type represents all possible errors that can occur when serializing or
7/// deserializing JS values.
8pub 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
20/// Alias for a `Result` with the error type `rquickjs_serde::Error`.
21pub 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/// The internal representation of an error.
50///
51/// This enum represents various errors that can occur during JS value serialization or deserialization,
52/// including UTF-8 conversion errors, and errors originating from the `rquickjs` library.
53#[derive(Debug)]
54pub enum ErrorImpl {
55    /// A generic error message
56    Message(String),
57    /// An error originating from the `rquickjs` library.
58    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, "{e}"),
86        }
87    }
88}
89
90impl From<&str> for ErrorImpl {
91    fn from(value: &str) -> Self {
92        ErrorImpl::Message(value.to_string())
93    }
94}
95
96impl From<JSError> for ErrorImpl {
97    fn from(value: JSError) -> Self {
98        ErrorImpl::Rquickjs(value)
99    }
100}
101
102/// An error type containing possible thrown exception values.
103#[derive(Debug)]
104pub enum CaughtError<'js> {
105    /// Error was an exception and an instance of Error
106    Exception(Exception<'js>),
107    /// Error was an exception but not an instance of Error.
108    Value(Value<'js>),
109    /// Error wasn't an exception
110    Error(JSError),
111    /// A generic error message
112    Message(String),
113}
114
115impl<'js> fmt::Display for CaughtError<'js> {
116    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117        match self {
118            CaughtError::Error(e) => e.fmt(f),
119            CaughtError::Exception(e) => e.fmt(f),
120            CaughtError::Value(e) => {
121                writeln!(f, "Exception generated by quickjs: {e:?}")
122            }
123            CaughtError::Message(msg) => write!(f, "{msg}"),
124        }
125    }
126}
127
128impl<'js> error::Error for CaughtError<'js> {}