easy_err/
err.rs

1use std::{
2    error, fmt,
3    fs::OpenOptions,
4    io::{self, Write},
5    path::Path,
6};
7
8pub use chrono::{DateTime, Local};
9use colored::Colorize;
10
11/// 用于统一错误的枚举
12///
13/// # Examples
14/// ```
15/// let err = easy_err::Error::custom("Here is a error.");
16/// err.report();
17/// ```
18#[derive(Debug)]
19pub enum Error {
20    /// 用于包装已经实现Error Trait的结构体或枚举
21    Basic(DateTime<Local>, Box<dyn error::Error>),
22    /// 用于报告用户自定义的错误信息
23    Custom(DateTime<Local>, String),
24}
25
26impl Error {
27    /// 获取错误发生的时间
28    ///
29    /// # Example
30    /// ```
31    /// let time = easy_err::Error::custom("Here is a custom error.").time();
32    /// println!("{}", time);
33    /// ```
34    pub fn time(&self) -> DateTime<Local> {
35        match self {
36            Self::Basic(time, _) => *time,
37            Self::Custom(time, _) => *time,
38        }
39    }
40
41    /// 产生一个basic变体
42    ///
43    /// # Examples
44    /// ```
45    /// let file = std::fs::File::open("An obvious mistake.").or_else(|err|{Err(easy_err::Error::basic(err))});
46    /// match file {
47    ///     Ok(_) => println!("Ok!"),
48    ///     Err(err) => {err.report();}
49    /// }
50    /// ```
51    pub fn basic(err: impl error::Error + 'static) -> Error {
52        Error::Basic(Local::now(), Box::new(err))
53    }
54
55    /// 产生一个custom变体
56	/// 
57	/// # Note
58	/// 推荐使用 `custom!()` 宏代替
59    ///
60    /// # Examples
61    /// ```
62    /// let custom_err = easy_err::Error::custom("Here is a error.");
63    /// custom_err.report();
64    /// ```
65    pub fn custom<S>(msg: S) -> Error
66    where
67        S: ToString,
68    {
69        Error::Custom(Local::now(), msg.to_string())
70    }
71
72    /// 在标准错误流中输出一条报告信息
73    ///
74    /// # Examples
75    /// ```
76    /// let custom_err = easy_err::Error::custom("Here is a error.");
77    /// custom_err.report();
78    /// // output:
79    /// // error:
80    /// //     time: <ErrorTime>
81    /// //      msg: 'Here is a error.'
82    /// ```
83    pub fn report(&self) -> &Self {
84        eprintln!("\n{}:{}", "error".red().bold(), self);
85        self
86    }
87
88    /// 引发 panic!() 宏
89    ///
90    /// # Examples
91    /// ```
92    /// let custom_err = easy_err::Error::custom("Here is a error.");
93    /// custom_err.panic();
94    /// // output:
95    /// // error:
96    /// //     time: <ErrorTime>
97    /// //      msg: 'Here is a error.'
98    /// ```
99    pub fn panic(&self) {
100        panic!("{}", self);
101    }
102
103    /// 将报告信息输出至文件
104    ///
105    /// # Params
106    /// - path: 任何可以转换为 Path 的值
107    ///
108    /// # Examples
109    /// ```
110    /// let custom_err = easy_err::Error::custom("Here is a error.");
111    /// custom_err.log_to("./log.txt");
112    /// ```
113    pub fn log_to<P>(&self, path: P) -> &Self
114    where
115        P: AsRef<Path>,
116    {
117        match OpenOptions::new().create(true).append(true).open(path) {
118            Ok(mut file) => {
119                if let Err(err) = writeln!(file, "error:{}", self) {
120                    Error::basic(err).report();
121                }
122            }
123            Err(err) => {
124                Error::basic(err).report();
125            }
126        }
127        self
128    }
129}
130
131impl fmt::Display for Error {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        match self {
134            Self::Basic(time, err) => write!(f, "\n\t time: {}\n\t  msg: {}\n", time, err),
135            Self::Custom(time, msg) => write!(f, "\n\t time: {}\n\t  msg: {}\n", time, msg),
136        }
137    }
138}
139
140impl error::Error for Error {
141    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
142        match self {
143            Self::Basic(.., err) => Some(err.as_ref()),
144            Self::Custom(..) => None,
145        }
146    }
147}
148
149impl From<io::Error> for Error {
150    fn from(value: io::Error) -> Self {
151        Self::basic(value)
152    }
153}
154
155impl From<fmt::Error> for Error {
156    fn from(value: fmt::Error) -> Self {
157        Self::basic(value)
158    }
159}
160
161impl From<&Self> for Error {
162	fn from(value: &Self) -> Self {
163		match value {
164			Error::Basic( time, err ) => Error::Basic(*time, Box::new(Error::custom(err.to_string()))),
165			Error::Custom(time, msg) => Error::Custom(*time, msg.to_string())
166
167		}
168	}
169}
170
171/// 用于方便地将Result<T, Error>当作Error处理
172///
173/// # Tips
174/// - 不建议为别的结构体或枚举实现此Trait,因为我自己还没完全搞清楚这个地方该怎么弄,这暂且还是一个实验性功能
175///
176/// # Example
177/// ```
178/// use std::fs;
179/// use easy_err::{Error, ErrResult};
180///
181/// fn test() -> Result<(), Error> {
182///     fs::File::open("An obvious mistake.")?;
183///     Ok(())
184/// }
185///
186/// test().panic();
187/// ```
188pub trait ErrResult<T> {
189    fn panic(self) -> T;
190}
191
192impl<T> ErrResult<T> for Result<T, Error> {
193    fn panic(self) -> T {
194        match self {
195            Ok(t) => t,
196            Err(err) => panic!("{}", err.to_string()),
197        }
198    }
199}