1use core::fmt;
2use serde::{Deserialize, Serialize};
3use std::{io::ErrorKind, string::FromUtf8Error};
4use thiserror::Error;
5
6use crate::{Result, Vars};
7
8#[derive(Deserialize, Serialize, Error, Debug, Clone, PartialEq)]
9pub enum ActError {
10 #[error("{0}")]
11 Convert(String),
12
13 #[error("{0}")]
14 Script(String),
15
16 #[error("ecode: {ecode}, message: {message}")]
17 Exception { ecode: String, message: String },
18
19 #[error("{0}")]
20 Model(String),
21
22 #[error("{0}")]
23 Runtime(String),
24
25 #[error("{0}")]
26 Adapter(String),
27
28 #[error("{0}")]
29 Store(String),
30
31 #[error("{0}")]
32 Action(String),
33
34 #[error("{0}")]
35 IoError(String),
36}
37
38#[derive(Default, Debug, Clone, Deserialize, Serialize)]
39pub struct Error {
40 #[serde(default)]
41 pub ecode: String,
42 #[serde(default)]
43 pub message: String,
44}
45
46impl fmt::Display for Error {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 let text = serde_json::to_string(self).unwrap();
49 f.write_str(&text)
50 }
51}
52
53impl Error {
54 pub fn new(message: &str, ecode: &str) -> Self {
55 Self {
56 message: message.to_string(),
57 ecode: ecode.to_string(),
58 }
59 }
60
61 pub fn from_var(value: &Vars) -> Result<Self> {
62 serde_json::from_value::<Self>(value.clone().into()).map_err(|err| err.into())
63 }
64}
65
66impl From<ActError> for String {
67 fn from(val: ActError) -> Self {
68 val.to_string()
69 }
70}
71
72impl From<ActError> for Error {
73 fn from(val: ActError) -> Self {
74 match val {
75 ActError::Exception { ecode, message } => Error { ecode, message },
76 err => Error {
77 ecode: "".to_string(),
78 message: err.to_string(),
79 },
80 }
81 }
82}
83
84impl From<std::io::Error> for ActError {
85 fn from(error: std::io::Error) -> Self {
86 ActError::IoError(error.to_string())
87 }
88}
89
90impl From<ActError> for std::io::Error {
91 fn from(val: ActError) -> Self {
92 std::io::Error::new(ErrorKind::Other, val.to_string())
93 }
94}
95
96impl From<rquickjs::Error> for ActError {
97 fn from(error: rquickjs::Error) -> Self {
98 ActError::Script(error.to_string())
99 }
100}
101
102impl From<ActError> for rquickjs::Error {
103 fn from(val: ActError) -> Self {
104 std::io::Error::other(val.to_string()).into()
105 }
106}
107
108impl From<FromUtf8Error> for ActError {
109 fn from(_: FromUtf8Error) -> Self {
110 ActError::Runtime("Error with utf-8 string convert".to_string())
111 }
112}
113
114impl From<serde_json::Error> for ActError {
115 fn from(error: serde_json::Error) -> Self {
116 ActError::Convert(error.to_string())
117 }
118}
119
120impl<'a> From<rquickjs::CaughtError<'a>> for ActError {
121 fn from(error: rquickjs::CaughtError<'a>) -> Self {
122 ActError::Script(error.to_string())
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use serde_json::json;
129
130 use crate::{ActError, Error, Vars};
131
132 #[test]
133 fn engine_error_default() {
134 let err = Error::default();
135 assert_eq!(err.message, "");
136 assert_eq!(err.ecode, "");
137 }
138
139 #[test]
140 fn engine_error_json_full() {
141 let err = Error::new("abc", "err1");
142 let v = serde_json::to_value(err).unwrap();
143 assert_eq!(v, json!({ "ecode": "err1", "message": "abc" }))
144 }
145
146 #[test]
147 fn engine_error_from_value() {
148 let err = Vars::new().with("ecode", "err1").with("message", "test");
149 let v = Error::from_var(&err).unwrap();
150 assert_eq!(v.ecode, "err1");
151 assert_eq!(v.message, "test");
152 }
153
154 #[test]
155 fn engine_act_error_into() {
156 let err = ActError::Action("error message".to_string());
157 let v: Error = err.into();
158 assert_eq!(v.message, "error message");
159 assert_eq!(v.ecode, "");
160 }
161
162 #[test]
163 fn engine_act_exception_into() {
164 let err = ActError::Exception {
165 ecode: "err1".to_string(),
166 message: "error message".to_string(),
167 };
168 let v: Error = err.into();
169 assert_eq!(v.message, "error message");
170 assert_eq!(v.ecode, "err1");
171 }
172}