1 // Copyright (c) 2018 Toby Smith <toby@tismith.id.au> 2 // 3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 4 // http://www.apache.org/license/LICENSE-2.0> or the MIT license 5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 6 // option. This file may not be copied, modified, or distributed 7 // except according to those terms. 8 9 #![deny( 10 missing_docs, 11 missing_debug_implementations, 12 missing_copy_implementations, 13 trivial_casts, 14 trivial_numeric_casts, 15 unreachable_pub, 16 unsafe_code, 17 unstable_features, 18 unused_extern_crates, 19 unused_import_braces, 20 unused_qualifications, 21 variant_size_differences 22 )] 23 24 //! Some newtype wrappers to help with using ? in main() 25 //! 26 //! The primary items exported by this library are: 27 //! 28 //! - `ExitFailure`: a wrapper around `failure::Error` to allow ? printing from main 29 //! to present a nicer error message, including any available context and backtrace. 30 //! 31 //! - `ExitDisplay<E>`: a wrapper around `E: std::fmt::Display` to allow the error message 32 //! from main to use `Display` and not `Debug` 33 //! 34 //! Basically, these types should only ever be used in the return type for 35 //! `main()` 36 //! 37 extern crate failure; 38 39 /// The newtype wrapper around `failure::Error` 40 /// 41 /// ```rust,should_panic 42 /// # extern crate failure; 43 /// # extern crate exitfailure; 44 /// # use failure::ResultExt; 45 /// # use exitfailure::ExitFailure; 46 /// fn main() -> Result<(), ExitFailure> { 47 /// Ok(some_fn()?) 48 /// } 49 /// 50 /// fn some_fn() -> Result<(), failure::Error> { 51 /// let error = Err(failure::err_msg("root cause failure")); 52 /// Ok(error.context("this is some context".to_string())?) 53 /// } 54 /// ``` 55 pub struct ExitFailure(failure::Error); 56 57 /// Prints a list of causes for this Error, along with any backtrace 58 /// information collected by the Error (if RUST_BACKTRACE=1). 59 impl std::fmt::Debug for ExitFailure { fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result60 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 61 let fail = self.0.as_fail(); 62 write!(f, "{}", fail)?; 63 64 for cause in fail.iter_causes() { 65 write!(f, "\nInfo: caused by {}", cause)?; 66 } 67 68 if let Ok(x) = std::env::var("RUST_BACKTRACE") { 69 if x != "0" { 70 write!(f, "\n{}", self.0.backtrace())? 71 } 72 } 73 74 Ok(()) 75 } 76 } 77 78 impl<T: Into<failure::Error>> From<T> for ExitFailure { from(t: T) -> Self79 fn from(t: T) -> Self { 80 ExitFailure(t.into()) 81 } 82 } 83 84 /// A newtype wrapper around `E: std::fmt::Display` 85 /// 86 /// ```rust,should_panic 87 /// # extern crate exitfailure; 88 /// # use exitfailure::ExitDisplay; 89 /// fn main() -> Result<(), ExitDisplay<String>> { 90 /// Ok(some_fn()?) 91 /// } 92 /// 93 /// fn some_fn() -> Result<(), String> { 94 /// Err("some error".into()) 95 /// } 96 /// ``` 97 pub struct ExitDisplay<E: std::fmt::Display>(E); 98 99 /// Prints the underlying error type, using `Display` and not `Debug`. 100 impl<E: std::fmt::Display> std::fmt::Debug for ExitDisplay<E> { fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result101 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 102 write!(f, "{}", self.0) 103 } 104 } 105 106 impl<E: std::fmt::Display> From<E> for ExitDisplay<E> { from(e: E) -> Self107 fn from(e: E) -> Self { 108 ExitDisplay(e) 109 } 110 } 111 112 #[cfg(test)] 113 mod test { 114 use super::*; 115 use std::fmt::Write; 116 117 #[test] test_exitfailure()118 fn test_exitfailure() { 119 let mut buffer = String::new(); 120 let error = failure::err_msg("some failure").context("some context"); 121 let exitfailure: ExitFailure = error.into(); 122 write!(buffer, "{:?}", exitfailure).unwrap(); 123 assert!(buffer.contains("some failure")); 124 assert!(buffer.contains("some context")); 125 } 126 127 #[test] test_exitdisplay()128 fn test_exitdisplay() { 129 let mut buffer = String::new(); 130 let error = "some error".to_string(); 131 let exitdisplay: ExitDisplay<String> = error.into(); 132 write!(buffer, "{:?}", exitdisplay).unwrap(); 133 assert_eq!(buffer, "some error"); 134 } 135 } 136