Guest User

Untitled

a guest
Dec 19th, 2018
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.64 KB | None | 0 0
  1. //////////////////////////////////////////////////////////////////////////////
  2. /// Crate chainerror
  3. //////////////////////////////////////////////////////////////////////////////
  4. use std::error::Error;
  5. use std::fmt::{self, Debug, Display, Formatter};
  6.  
  7. pub struct ChainError<T> {
  8. occurrence: Option<(u32, &'static str)>,
  9. kind: T,
  10. error_cause: Option<Box<dyn Error + 'static>>,
  11. }
  12.  
  13. impl<T: 'static + Display + Debug> ChainError<T> {
  14. pub fn new(
  15. kind: T,
  16. error_cause: Option<Box<dyn Error + 'static>>,
  17. occurrence: Option<(u32, &'static str)>,
  18. ) -> Self {
  19. Self {
  20. occurrence,
  21. kind,
  22. error_cause,
  23. }
  24. }
  25.  
  26. pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
  27. let mut cause = self as &(dyn Error + 'static);
  28. while let Some(c) = cause.source() {
  29. cause = c;
  30. }
  31. Some(cause)
  32. }
  33.  
  34. pub fn find_cause<U: Error + 'static>(&self) -> Option<&(dyn Error + 'static)> {
  35. let mut cause = self as &(dyn Error + 'static);
  36. loop {
  37. if cause.is::<U>() {
  38. return Some(cause);
  39. }
  40.  
  41. match cause.source() {
  42. Some(c) => cause = c,
  43. None => return None,
  44. }
  45. }
  46. }
  47.  
  48. pub fn find_kind<U: 'static + Display + Debug>(&self) -> Option<&ChainError<U>> {
  49. let mut cause = self as &(dyn Error + 'static);
  50. loop {
  51. if cause.is::<ChainError<U>>() {
  52. return cause.downcast_ref::<ChainError<U>>();
  53. }
  54.  
  55. match cause.source() {
  56. Some(c) => cause = c,
  57. None => return None,
  58. }
  59. }
  60. }
  61.  
  62. pub fn kind<'a>(&'a self) -> &'a T {
  63. &self.kind
  64. }
  65. }
  66.  
  67. impl<T: 'static + Display + Debug> Error for ChainError<T> {
  68. fn source(&self) -> Option<&(dyn Error + 'static)> {
  69. if let Some(ref e) = self.error_cause {
  70. Some(e.as_ref())
  71. } else {
  72. None
  73. }
  74. }
  75. }
  76.  
  77. impl<T: 'static + Display + Debug> Display for ChainError<T> {
  78. fn fmt(&self, f: &mut Formatter) -> fmt::Result {
  79. write!(f, "{}", self.kind)?;
  80.  
  81. if let Some(e) = self.source() {
  82. writeln!(f, "\nCaused by:")?;
  83. Display::fmt(&e, f)?;
  84. }
  85. Ok(())
  86. }
  87. }
  88.  
  89. impl<T: 'static + Display + Debug> Debug for ChainError<T> {
  90. fn fmt(&self, f: &mut Formatter) -> fmt::Result {
  91. if let Some(o) = self.occurrence {
  92. write!(f, "{}:{}: ", o.1, o.0)?;
  93. }
  94.  
  95. Debug::fmt(&self.kind, f)?;
  96.  
  97. if let Some(e) = self.source() {
  98. writeln!(f, "\nCaused by:")?;
  99. Debug::fmt(&e, f)?;
  100. }
  101. Ok(())
  102. }
  103. }
  104.  
  105. #[macro_export]
  106. macro_rules! cherr {
  107. ( $k:expr ) => {
  108. ChainError::<_>::new($k, None, Some((line!(), file!())))
  109. };
  110. ( $e:expr, $k:expr ) => {
  111. ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
  112. };
  113. }
  114.  
  115. #[macro_export]
  116. macro_rules! mstrerr {
  117. ( $t:ident, $v:expr $(, $more:expr)* ) => {
  118. |e| cherr!(e, $t (format!($v, $( $more , )* )))
  119. };
  120. ( $t:path, $v:expr $(, $more:expr)* ) => {
  121. |e| cherr!(e, $t (format!($v, $( $more , )* )))
  122. };
  123. }
  124.  
  125. #[macro_export]
  126. macro_rules! derive_str_cherr {
  127. ($e:ident) => {
  128. struct $e(String);
  129. impl ::std::fmt::Display for $e {
  130. fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
  131. write!(f, "{}", self.0)
  132. }
  133. }
  134. impl ::std::fmt::Debug for $e {
  135. fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
  136. write!(f, "{}({})", stringify!($e), self.0)
  137. }
  138. }
  139. };
  140. }
  141.  
  142. //////////////////////////////////////////////////////////////////////////////
  143. /// Example
  144. //////////////////////////////////////////////////////////////////////////////
  145.  
  146. use std::io::Error as IoError;
  147. use std::io::ErrorKind as IoErrorKind;
  148. use std::path::Path;
  149.  
  150. #[derive(Clone, PartialEq, Debug)]
  151. enum ParseError {
  152. InvalidValue(u32),
  153. InvalidParameter(String),
  154. NoOpen,
  155. NoClose,
  156. }
  157.  
  158. impl ::std::fmt::Display for ParseError {
  159. fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
  160. match self {
  161. ParseError::InvalidValue(a) => write!(f, "InvalidValue: {}", a),
  162. ParseError::InvalidParameter(a) => write!(f, "InvalidParameter: '{}'", a),
  163. ParseError::NoOpen => write!(f, "No opening '{{' in config file"),
  164. ParseError::NoClose => write!(f, "No closing '}}' in config file"),
  165. }
  166. }
  167. }
  168.  
  169. fn parse_config(c: String) -> Result<(), Box<Error>> {
  170. if !c.starts_with('{') {
  171. Err(cherr!(ParseError::NoOpen))?;
  172. }
  173. if !c.ends_with('}') {
  174. Err(cherr!(ParseError::NoClose))?;
  175. }
  176. let c = &c[1..(c.len() - 1)];
  177. let v = c
  178. .parse::<u32>()
  179. .map_err(|e| cherr!(e, ParseError::InvalidParameter(c.into())))?;
  180. if v > 100 {
  181. Err(cherr!(ParseError::InvalidValue(v)))?;
  182. }
  183. Ok(())
  184. }
  185.  
  186. derive_str_cherr!(ConfigFileError);
  187. derive_str_cherr!(SeriousError);
  188. derive_str_cherr!(FileError);
  189. derive_str_cherr!(AppError);
  190.  
  191. fn file_reader(filename: &Path) -> Result<(), Box<Error>> {
  192. Err(IoError::from(IoErrorKind::NotFound)).map_err(mstrerr!(
  193. FileError,
  194. "Can't find {:?}",
  195. filename
  196. ))?;
  197. Ok(())
  198. }
  199.  
  200. fn read_config(filename: &Path) -> Result<(), Box<Error>> {
  201. if filename.eq(Path::new("global.ini")) {
  202. // assume we got an IO error
  203. file_reader(filename).map_err(mstrerr!(ConfigFileError, "Can't find {:?}", filename))?;
  204. }
  205. // assume we read some buffer
  206. if filename.eq(Path::new("local.ini")) {
  207. let buf = String::from("{1000}");
  208. parse_config(buf)?;
  209. }
  210.  
  211. if filename.eq(Path::new("user.ini")) {
  212. let buf = String::from("foo");
  213. parse_config(buf)?;
  214. }
  215.  
  216. if filename.eq(Path::new("user2.ini")) {
  217. let buf = String::from("{foo");
  218. parse_config(buf)?;
  219. }
  220.  
  221. if filename.eq(Path::new("user3.ini")) {
  222. let buf = String::from("{foo}");
  223. parse_config(buf)?;
  224. }
  225.  
  226. if filename.eq(Path::new("custom.ini")) {
  227. let buf = String::from("{10}");
  228. parse_config(buf)?;
  229. }
  230.  
  231. if filename.eq(Path::new("essential.ini")) {
  232. Err(cherr!(SeriousError("Something is really wrong".into())))?;
  233. }
  234.  
  235. Ok(())
  236. }
  237.  
  238. fn read_verbose_config(p: &str) -> Result<(), ChainError<AppError>> {
  239. eprintln!("Reading '{}' ... ", p);
  240. read_config(Path::new(p)).map_err(mstrerr!(AppError, "{}", p))?;
  241. eprintln!("Ok reading {}", p);
  242. Ok(())
  243. }
  244.  
  245. fn start_app(debug: bool) -> Result<(), Box<Error>> {
  246. for p in &[
  247. "global.ini",
  248. "local.ini",
  249. "user.ini",
  250. "user2.ini",
  251. "user3.ini",
  252. "custom.ini",
  253. "essential.ini",
  254. ] {
  255. if let Err(e) = read_verbose_config(p) {
  256. if e.find_kind::<SeriousError>().is_some() {
  257. // Bail out on SeriousError
  258. eprintln!("---> Serious Error:\n{:?}", e);
  259. Err(cherr!(e, AppError("Seriously".into())))?;
  260. } else if let Some(cfg_error) = e.find_kind::<ConfigFileError>() {
  261. if debug {
  262. eprintln!("{:?}\n", cfg_error);
  263. } else {
  264. // Deep Error handling
  265. if let Some(chioerror) = cfg_error.find_kind::<IoError>() {
  266. let ioerror = chioerror.kind();
  267. match ioerror.kind() {
  268. IoErrorKind::NotFound => {
  269. eprint!("Ignoring missing file");
  270. if let Some(root_cause) = cfg_error.root_cause() {
  271. eprint!(", because of: {}\n", root_cause);
  272. }
  273. eprintln!();
  274. }
  275. _ => Err(cherr!(e, AppError("Unhandled IOError".into())))?,
  276. }
  277. } else {
  278. eprintln!("ConfigFileError for: {}", e);
  279. }
  280. }
  281. } else {
  282. if debug {
  283. eprintln!("Error reading:\n{:?}\n", e)
  284. } else {
  285. eprintln!("Error reading: {}\n", e)
  286. }
  287. }
  288. }
  289. eprintln!();
  290. }
  291. Ok(())
  292. }
  293.  
  294. fn main() {
  295. eprintln!("Display:\n");
  296. let e = start_app(false).unwrap_err();
  297. assert!(e.is::<ChainError<AppError>>());
  298. eprintln!("\n\n==================================");
  299. eprintln!("==== Debug output");
  300. eprintln!("==================================\n");
  301. let r = start_app(true);
  302. assert!(r.unwrap_err().is::<ChainError<AppError>>());
  303. }
Add Comment
Please, Sign In to add comment