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}