valico/common/
error.rs
1use std::error::Error;
2use std::fmt::Debug;
3use std::any::{Any, TypeId};
4use std::mem;
5use serde::{Serialize, Serializer};
6use serde_json::{Value, to_value};
7
8pub trait GetTypeId: Any { fn typeid(&self) -> TypeId { TypeId::of::<Self>() } }
9impl<T: Any> GetTypeId for T {}
10
11pub fn get_data_ptr<T: ?Sized>(d: *const T) -> *const () {
12 d as *const ()
13}
14
15pub trait ValicoError : Error + Send + Debug + GetTypeId {
16 fn get_code(&self) -> &str;
17 fn get_path(&self) -> &str;
18 fn get_title(&self) -> &str;
19 fn get_detail(&self) -> Option<&str> { None }
20}
21
22impl ValicoError {
23 pub fn is<E: ValicoError>(&self) -> bool { self.typeid() == TypeId::of::<E>() }
25
26 pub fn downcast<E: ValicoError>(&self) -> Option<&E> {
28 if self.is::<E>() {
29 unsafe { Some(mem::transmute(get_data_ptr(self))) }
30 } else {
31 None
32 }
33 }
34}
35
36impl Serialize for ValicoError {
37 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
38 let mut map = ::serde_json::Map::new();
39 map.insert("code".to_string(), to_value(self.get_code()).unwrap());
40 map.insert("title".to_string(), to_value(self.get_title()).unwrap());
41 map.insert("path".to_string(), to_value(self.get_path()).unwrap());
42 match self.get_detail() {
43 Some(ref detail) => { map.insert("detail".to_string(), to_value(detail).unwrap()); },
44 None => ()
45 }
46 Value::Object(map).serialize(serializer)
47 }
48}
49
50pub type ValicoErrors = Vec<Box<ValicoError>>;
51
52macro_rules! impl_basic_err {
53 ($err:ty, $code:expr) => {
54 impl ::std::error::Error for $err {
55 fn description(&self) -> &str {
56 $code
57 }
58 }
59
60 impl ::std::fmt::Display for $err {
61 fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
62 self.description().fmt(formatter)
63 }
64 }
65 }
66}
67
68macro_rules! impl_err {
69 ($err:ty, $code:expr, $title:expr) => {
70 impl_basic_err!($err, $code);
71
72 impl $crate::common::error::ValicoError for $err {
73 fn get_code(&self) -> &str { $code }
74 fn get_title(&self) -> &str { $title }
75 fn get_path(&self) -> &str { self.path.as_ref() }
76 }
77 };
78
79 ($err:ty, $code:expr, $title:expr, +detail) => {
80 impl_basic_err!($err, $code);
81
82 impl $crate::common::error::ValicoError for $err {
83 fn get_code(&self) -> &str { $code }
84 fn get_title(&self) -> &str { $title }
85 fn get_path(&self) -> &str { self.path.as_ref() }
86 fn get_detail(&self) -> Option<&str> { Some(self.detail.as_ref()) }
87 }
88 };
89
90 ($err:ty, $code:expr, $title:expr, +opt_detail) => {
91 impl_basic_err!($err, $code);
92
93 impl $crate::common::error::ValicoError for $err {
94 fn get_code(&self) -> &str { $code }
95 fn get_title(&self) -> &str { $title }
96 fn get_path(&self) -> &str { self.path.as_ref() }
97 fn get_detail(&self) -> Option<&str> { self.detail.as_ref().map(|s| s.as_ref()) }
98 }
99 }
100}
101
102macro_rules! impl_serialize{
103 ($err:ty) => {
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 match self.get_detail() {
111 Some(ref detail) => { map.insert("detail".to_string(), to_value(detail).unwrap()); },
112 None => ()
113 }
114 Value::Object(map).serialize(serializer)
115 }
116 }
117 };
118 ($err:ty, $($sp:expr),+) => {
119 impl Serialize for $err {
120 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
121 let mut map = ::serde_json::Map::new();
122 map.insert("code".to_string(), to_value(self.get_code()).unwrap());
123 map.insert("title".to_string(), to_value(self.get_title()).unwrap());
124 map.insert("path".to_string(), to_value(self.get_path()).unwrap());
125 match self.get_detail() {
126 Some(ref detail) => { map.insert("detail".to_string(), to_value(detail).unwrap()); },
127 None => ()
128 }
129 $({
130 let closure = $sp;
131 closure(self, &mut map);
132 })+
133 Value::Object(map).serialize(serializer)
134 }
135 }
136 }
137}