1mod utils;
17use thiserror::Error;
18
19use serde::{Serialize, Deserialize};
20
21use utils::{ type_of, struct_name };
22
23
24#[derive(Debug, Serialize, Deserialize)]
26pub struct EssencePackage<T, M> {
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub metadata: Option<M>,
29 pub payload: T,
30}
31
32#[derive(Debug, Serialize, Deserialize)]
34pub struct ErrorPayload {
35 pub kind: String,
36 pub error: String,
37 pub message: String,
38 pub stack: Vec<String>,
39}
40
41impl<T> From<&T> for ErrorPayload
42where
43 T: std::error::Error
44{
45 fn from(error: &T) -> Self {
46 let kind = type_of(&error);
47 let name = struct_name(&error);
48
49 ErrorPayload {
50 kind: kind,
51 error: name,
52 message: format!("{}", error),
53 stack: vec![],
54 }
55 }
56}
57
58
59#[derive(Debug, Error)]
61pub enum EssenceError {
62 #[error("[{0}::{1}( {2} )]")]
63 ErrorPayload(String, String, String),
64}
65
66pub type EssenceErrorPackage<M> = EssencePackage<ErrorPayload, M>;
68
69
70#[derive(Debug, Serialize, Deserialize)]
72#[serde(tag = "type")]
73#[serde(rename_all = "lowercase")]
74pub enum EssenceResponse<P, PM, EM> {
75 Success(EssencePackage<P, PM>),
76 Failure(EssenceErrorPackage<EM>),
77}
78
79
80impl<P, PM, EM> EssenceResponse<P, PM, EM> {
81 pub fn new<E>(payload: Result<P, E>, success_metadata: Option<PM>, error_metadata: Option<EM>, ) -> Self
82 where
83 E: std::error::Error {
84 match payload {
85 Ok(data) => EssenceResponse::Success(EssencePackage {
86 metadata: success_metadata,
87 payload: data,
88 }),
89 Err(error) => EssenceResponse::Failure(EssencePackage {
90 metadata: error_metadata,
91 payload: ErrorPayload::from( &error ),
92 }),
93 }
94 }
95
96 pub fn success(payload: P, metadata: Option<PM>) -> Self {
97 EssenceResponse::Success(EssencePackage {
98 metadata: metadata,
99 payload: payload,
100 })
101 }
102
103 pub fn failure(error: ErrorPayload, metadata: Option<EM>) -> Self {
104 EssenceResponse::Failure(EssencePackage {
105 metadata: metadata,
106 payload: error,
107 })
108 }
109
110 pub fn as_result(self) -> Result<P, EssenceError> {
111 match self {
112 EssenceResponse::Success(pack) => Ok(pack.payload),
113 EssenceResponse::Failure(pack) => Err(EssenceError::ErrorPayload(pack.payload.kind.clone(), pack.payload.error.clone(), pack.payload.message.clone())),
114 }
115 }
116}
117
118
119#[cfg(test)]
120pub mod tests {
121 use super::*;
122
123 use serde_json::json;
124 use std::fmt;
125 use thiserror::Error;
126
127 #[test]
128 fn type_of_test() {
130 let vector = vec![1,2,3,4];
131
132 assert_eq!(
133 type_of(&vector),
134 String::from("Vec<i32>") );
135 }
136
137 #[test]
138 fn struct_name_test() {
140 let vector = vec![1,2,3,4];
141
142 assert_eq!(
143 struct_name(&vector),
144 String::from("Error") );
145 }
146
147 #[test]
148 fn enum_test() {
150 #[derive(Debug, Error)]
151 enum AppError<'a> {
152 #[error("This is so bad input: {0}")]
153 BadInput(&'a str),
154 }
155
156 let error = AppError::BadInput("This is so bad...");
157 let payload = ErrorPayload::from( &error );
158
159 assert_eq!(
160 serde_json::to_string_pretty( &json!(payload) ).unwrap(),
161 String::from(r#"{
162 "error": "BadInput",
163 "kind": "AppError",
164 "message": "This is so bad input: This is so bad...",
165 "stack": []
166}"#));
167 println!("{:?}", error );
168 }
169
170 #[test]
171 fn struct_test() {
173 #[derive(Debug, Error)]
174 struct MyError {
175 msg: String,
176 }
177
178 impl fmt::Display for MyError {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 write!(f, "{}", self.msg)
181 }
182 }
183
184 let error = MyError { msg: "EntryHash(uhCEkNBaVvGRYmJUqsGNrfO8jC9Ij-t77QcmnAk3E3B8qh6TU09QN)".into() };
185 let payload = ErrorPayload::from( &error );
186
187 assert_eq!(
188 serde_json::to_string_pretty( &json!(payload) ).unwrap(),
189 String::from(r#"{
190 "error": "MyError",
191 "kind": "MyError",
192 "message": "EntryHash(uhCEkNBaVvGRYmJUqsGNrfO8jC9Ij-t77QcmnAk3E3B8qh6TU09QN)",
193 "stack": []
194}"#));
195 println!("{:?}", error );
196 }
197
198 #[test]
199 fn tuple_test() {
201 #[derive(Debug, Error)]
202 struct MyError<'a>(&'a str, String);
203
204 impl<'a> fmt::Display for MyError<'a> {
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 write!(f, "{}: {}", self.0, self.1 )
207 }
208 }
209
210 let error = MyError( "BadInput", "This is so bad...".into() );
211 let payload = ErrorPayload::from( &error );
212
213 assert_eq!(
214 serde_json::to_string_pretty( &json!(payload) ).unwrap(),
215 String::from(r#"{
216 "error": "MyError",
217 "kind": "MyError",
218 "message": "BadInput: This is so bad...",
219 "stack": []
220}"#));
221 println!("{:?}", error );
222 }
223}