Guest User

Untitled

a guest
Dec 18th, 2018
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.93 KB | None | 0 0
  1. pub trait ChainError: Sized {
  2. fn new(
  3. line: u32,
  4. filename: &'static str,
  5. description: Option<String>,
  6. error_cause: Option<Box<dyn std::error::Error + 'static>>,
  7. ) -> Self;
  8. fn get_description() -> Option<String>;
  9. fn root_cause(&self) -> Option<&(dyn std::error::Error + 'static)>;
  10. fn find_cause<T: ::std::error::Error + 'static>(
  11. &self,
  12. ) -> Option<&(dyn std::error::Error + 'static)>;
  13. }
  14.  
  15. pub trait ChainErrorFrom<T>: ChainError {
  16. fn chain_error_from(_: T, _: u32, _: &'static str, _: Option<String>) -> Self;
  17. }
  18.  
  19. pub trait IntoChainError<T: ChainError>: Sized {
  20. fn into_chain_error(self, line: u32, filename: &'static str, description: Option<String>) -> T;
  21. }
  22.  
  23. impl<T, U> IntoChainError<U> for T
  24. where
  25. U: ChainErrorFrom<T> + ChainError,
  26. {
  27. fn into_chain_error(self, line: u32, filename: &'static str, description: Option<String>) -> U {
  28. U::chain_error_from(self, line, filename, description)
  29. }
  30. }
  31.  
  32. impl<T: ChainError> ChainErrorFrom<Box<std::error::Error>> for T {
  33. fn chain_error_from(
  34. e: Box<std::error::Error>,
  35. line: u32,
  36. filename: &'static str,
  37. description: Option<String>,
  38. ) -> Self {
  39. <T>::new(line, filename, description, Some(e))
  40. }
  41. }
  42.  
  43. impl<T: ChainError > ::std::error::Error for T {
  44. fn description(&self) -> &str {
  45. if let Some(ref d) = self.get_description() {
  46. d.as_ref()
  47. } else {
  48. ""
  49. }
  50. }
  51. fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
  52. if let Some(ref e) = self.error_cause {
  53. Some(e.as_ref())
  54. } else {
  55. None
  56. }
  57. }
  58. }
  59. #[macro_export]
  60. macro_rules! chain_error_fn {
  61. ( $t:ident, $v:expr $(, $more:expr)* ) => {
  62. |e| <$t> :: new(line!(), file!(), Some(format!($v, $( $more , )* )), Some(e.into()))
  63. };
  64. ( $t:path, $v:expr $(, $more:expr)* ) => {
  65. |e| <$t> :: new(line!(), file!(), Some(format!($v, $( $more , )* )), Some(e.into()))
  66. };
  67. ( $t:ident) => {
  68. |e| <$t> :: new(line!(), file!(), None, Some(e.into()))
  69. };
  70. ( $t:path) => {
  71. |e| <$t> :: new(line!(), file!(), None, Some(e.into()))
  72. };
  73. }
  74.  
  75. #[macro_export]
  76. macro_rules! into_boxed_chain_error_fn {
  77. ( $v:expr $(, $more:expr)* ) => {
  78. |e| Box::<Error>::from(e).into_chain_error(line!(), file!(), Some(format!($v, $( $more , )* )))
  79. };
  80. ( ) => {
  81. |e| Box::<Error>::from(e).into_chain_error(line!(), file!(), None)
  82. };
  83. }
  84.  
  85. #[macro_export]
  86. macro_rules! chain {
  87. ( $v:expr $(, $more:expr)* ) => {
  88. |e| Box::<Error>::from(e).into_chain_error(line!(), file!(), Some(format!($v, $( $more , )* )))
  89. };
  90. ( ) => {
  91. |e| Box::<Error>::from(e).into_chain_error(line!(), file!(), None)
  92. };
  93. }
  94.  
  95. #[macro_export]
  96. macro_rules! into_chain_error_fn {
  97. ( $v:expr $(, $more:expr)* ) => {
  98. |e| e.into_chain_error(line!(), file!(), Some(format!($v, $( $more , )* )))
  99. };
  100. ( ) => {
  101. |e| e.into_chain_error(line!(), file!(), None)
  102. };
  103. }
  104.  
  105. #[macro_export]
  106. macro_rules! chain_error_from_fn {
  107. ( $t:expr, $v:expr $(, $more:expr)* ) => {
  108. |e| ($t).into().chain_error_from(e, line!(), file!(), Some(format!($v, $( $more , )* )))
  109. };
  110.  
  111. ( $t:expr ) => {
  112. |e| ($t).into().chain_error_from(e, line!(), file!(), None)
  113. };
  114. }
  115.  
  116. #[macro_export]
  117. macro_rules! chain_error {
  118. ( $t:ident, $v:expr $(, $more:expr)* ) => {
  119. <$t> :: new(line!(), file!(), Some(format!($v, $( $more , )*)), None)
  120. };
  121. ( $t:path, $v:expr $(, $more:expr)* ) => {
  122. <$t> :: new(line!(), file!(), Some(format!($v, $( $more , )*)), None)
  123. };
  124. }
  125.  
  126. #[macro_export]
  127. macro_rules! into_chain_error {
  128. ( $t:expr, $v:expr $(, $more:expr)* ) => {
  129. $t . into_chain_error(line!(), file!(), Some(format!($v, $( $more , )*)))
  130. };
  131. ( $t:expr ) => {
  132. $t . into_chain_error(line!(), file!(), None)
  133. };
  134. }
  135.  
  136. #[macro_export]
  137. macro_rules! derive_chain_error {
  138. ($e:ident) => {
  139. pub struct $e {
  140. line: u32,
  141. filename: &'static str,
  142. description: Option<String>,
  143. error_cause: Option<Box<dyn std::error::Error + 'static>>,
  144. }
  145.  
  146. impl ChainError for $e {
  147. fn new(
  148. line: u32,
  149. filename: &'static str,
  150. description: Option<String>,
  151. error_cause: Option<Box<dyn std::error::Error + 'static>>,
  152. ) -> Self {
  153. $e {
  154. line,
  155. filename,
  156. description,
  157. error_cause,
  158. }
  159. }
  160.  
  161. fn root_cause(&self) -> Option<&(dyn std::error::Error + 'static)> {
  162. let mut cause = self as &(dyn std::error::Error + 'static);
  163. while let Some(c) = cause.source() {
  164. cause = c;
  165. }
  166. Some(cause)
  167. }
  168.  
  169. fn find_cause<T: ::std::error::Error + 'static>(
  170. &self,
  171. ) -> Option<&(dyn std::error::Error + 'static)> {
  172. let mut cause = self as &(dyn std::error::Error + 'static);
  173. loop {
  174. if cause.is::<T>() {
  175. return Some(cause);
  176. }
  177.  
  178. match cause.source() {
  179. Some(c) => cause = c,
  180. None => return None,
  181. }
  182. }
  183. }
  184. }
  185.  
  186. impl ::std::fmt::Display for $e {
  187. fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
  188. writeln!(f, "{}", self.description())?;
  189. if let Some(e) = self.source() {
  190. writeln!(f, "\nCaused by:")?;
  191. ::std::fmt::Display::fmt(&e, f)?;
  192. }
  193. Ok(())
  194. }
  195. }
  196.  
  197. impl ::std::fmt::Debug for $e {
  198. fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
  199. writeln!(f, "{}:{}: {}", self.filename, self.line, self.description())?;
  200. if let Some(e) = self.source() {
  201. writeln!(f, "\nCaused by:")?;
  202. ::std::fmt::Debug::fmt(&e, f)?;
  203. }
  204. Ok(())
  205. }
  206. }
  207. };
  208. }
  209.  
  210. pub mod prelude {
  211. pub use super::{
  212. chain_error, chain_error_fn, chain_error_from_fn, derive_chain_error, into_chain_error,
  213. into_chain_error_fn, ChainError, ChainErrorFrom, IntoChainError,
  214. };
  215. }
  216.  
  217. #[cfg(test)]
  218. mod tests {
  219. use std::error::Error;
  220.  
  221. use crate::prelude::*;
  222.  
  223. derive_chain_error!(MyError);
  224. derive_chain_error!(MyMainError);
  225.  
  226. fn throw_error() -> Result<(), MyError> {
  227. let directory = String::from("ldfhgdfkgjdf");
  228. ::std::fs::remove_dir(&directory).map_err(chain!(
  229. "Could not remove directory '{}'{}",
  230. &directory,
  231. "!"
  232. ))?;
  233. Ok(())
  234. }
  235.  
  236. #[test]
  237. fn test_chain_error_fn() -> Result<(), MyMainError> {
  238. let res = throw_error().map_err(chain_error_fn!(MyMainError, "I has an error."));
  239.  
  240. if let Err(my_err) = res {
  241. if let Some(source) = my_err.source() {
  242. assert!(source.is::<MyError>());
  243. }
  244. println!("\nRoot cause is {:#?}\n", my_err.root_cause());
  245. assert!(my_err.root_cause().unwrap().is::<::std::io::Error>());
  246. assert!(my_err.find_cause::<::std::io::Error>().is_some());
  247.  
  248. if my_err.find_cause::<::std::io::Error>().is_some() {
  249. println!("Has cause io::Error");
  250. }
  251. if my_err.find_cause::<MyError>().is_some() {
  252. println!("Has cause MyError");
  253. }
  254. println!("-----------");
  255. println!("Display Error:\n{}", my_err);
  256. println!("-----------");
  257. println!("Debug Error: \n{:#?}", my_err);
  258. println!("-----------");
  259. };
  260. //res?;
  261. Ok(())
  262. }
  263. #[test]
  264. fn test_into_chain_error_fn() -> Result<(), MyMainError> {
  265. let res: Result<(), MyMainError> =
  266. throw_error().map_err(into_boxed_chain_error_fn!("I has an error."));
  267.  
  268. if let Err(my_err) = res {
  269. if let Some(source) = my_err.source() {
  270. assert!(source.is::<MyError>());
  271. }
  272. println!("\nRoot cause is {:#?}\n", my_err.root_cause());
  273. assert!(my_err.root_cause().unwrap().is::<::std::io::Error>());
  274. assert!(my_err.find_cause::<::std::io::Error>().is_some());
  275.  
  276. if my_err.find_cause::<::std::io::Error>().is_some() {
  277. println!("Has cause io::Error");
  278. }
  279. if my_err.find_cause::<MyError>().is_some() {
  280. println!("Has cause MyError");
  281. }
  282. println!("-----------");
  283. println!("Display Error:\n{}", my_err);
  284. println!("-----------");
  285. println!("Debug Error: \n{:#?}", my_err);
  286. println!("-----------");
  287. };
  288. //res?;
  289. Ok(())
  290. }
  291.  
  292. #[test]
  293. fn test_map_chain_err() -> Result<(), MyMainError> {
  294. let res: Result<(), MyMainError> = throw_error().map_err(chain!());
  295.  
  296. if let Err(my_err) = res {
  297. if let Some(source) = my_err.source() {
  298. assert!(source.is::<MyError>());
  299. }
  300. println!("\nRoot cause is {:#?}\n", my_err.root_cause());
  301. assert!(my_err.root_cause().unwrap().is::<::std::io::Error>());
  302. assert!(my_err.find_cause::<::std::io::Error>().is_some());
  303.  
  304. if my_err.find_cause::<::std::io::Error>().is_some() {
  305. println!("Has cause io::Error");
  306. }
  307. if my_err.find_cause::<MyError>().is_some() {
  308. println!("Has cause MyError");
  309. }
  310. println!("-----------");
  311. println!("Display Error:\n{}", my_err);
  312. println!("-----------");
  313. println!("Debug Error: \n{:#?}", my_err);
  314. println!("-----------");
  315. };
  316. //res?;
  317. Ok(())
  318. }
  319. }
Add Comment
Please, Sign In to add comment