1use std::error::Error;
2use std::fmt::Debug;
3
4use downcast_rs::Downcast;
5
6pub trait ValicoError: Downcast + Error + Send + Debug + erased_serde::Serialize {
7 fn get_code(&self) -> &str;
8 fn get_path(&self) -> &str;
9 fn get_title(&self) -> &str;
10 fn get_detail(&self) -> Option<&str> {
11 None
12 }
13}
14
15erased_serde::serialize_trait_object!(ValicoError);
16downcast_rs::impl_downcast!(ValicoError);
17
18pub type ValicoErrors = Vec<Box<dyn ValicoError>>;
19
20macro_rules! impl_basic_err {
21 ($err:ty, $code:expr) => {
22 impl ::std::error::Error for $err {}
23
24 impl ::std::fmt::Display for $err {
25 fn fmt(&self, formatter: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
26 write!(formatter, $code)
27 }
28 }
29 };
30}
31
32macro_rules! impl_err {
33 ($err:ty, $code:expr, $title:expr) => {
34 impl_basic_err!($err, $code);
35
36 impl $crate::common::error::ValicoError for $err {
37 fn get_code(&self) -> &str {
38 $code
39 }
40 fn get_title(&self) -> &str {
41 $title
42 }
43 fn get_path(&self) -> &str {
44 self.path.as_ref()
45 }
46 }
47 };
48
49 ($err:ty, $code:expr, $title:expr, +detail) => {
50 impl_basic_err!($err, $code);
51
52 impl $crate::common::error::ValicoError for $err {
53 fn get_code(&self) -> &str {
54 $code
55 }
56 fn get_title(&self) -> &str {
57 $title
58 }
59 fn get_path(&self) -> &str {
60 self.path.as_ref()
61 }
62 fn get_detail(&self) -> Option<&str> {
63 Some(self.detail.as_ref())
64 }
65 }
66 };
67
68 ($err:ty, $code:expr, $title:expr, +opt_detail) => {
69 impl_basic_err!($err, $code);
70
71 impl $crate::common::error::ValicoError for $err {
72 fn get_code(&self) -> &str {
73 $code
74 }
75 fn get_title(&self) -> &str {
76 $title
77 }
78 fn get_path(&self) -> &str {
79 self.path.as_ref()
80 }
81 fn get_detail(&self) -> Option<&str> {
82 self.detail.as_ref().map(|s| s.as_ref())
83 }
84 }
85 };
86}
87
88macro_rules! impl_serialize {
89 ($err:ty) => {
90 impl Serialize for $err {
91 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
92 let mut map = ::serde_json::Map::new();
93 map.insert("code".to_string(), to_value(self.get_code()).unwrap());
94 map.insert("title".to_string(), to_value(self.get_title()).unwrap());
95 map.insert("path".to_string(), to_value(self.get_path()).unwrap());
96 if let Some(ref detail) = self.get_detail() {
97 map.insert("detail".to_string(), to_value(detail).unwrap());
98 }
99 Value::Object(map).serialize(serializer)
100 }
101 }
102 };
103 ($err:ty, $($sp:expr),+) => {
104 impl Serialize for $err {
105 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
106 let mut map = ::serde_json::Map::new();
107 map.insert("code".to_string(), to_value(self.get_code()).unwrap());
108 map.insert("title".to_string(), to_value(self.get_title()).unwrap());
109 map.insert("path".to_string(), to_value(self.get_path()).unwrap());
110 if let Some(ref detail) = self.get_detail() {
111 map.insert("detail".to_string(), to_value(detail).unwrap());
112 }
113 $({
114 let closure = $sp;
115 closure(self, &mut map);
116 })+
117 Value::Object(map).serialize(serializer)
118 }
119 }
120 }
121}