1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 //! Defines errors that would be returned by the runtime during execution.
15 
16 use std::fmt::{Debug, Display, Formatter};
17 use std::io;
18 
19 /// Schedule errors during the execution.
20 pub struct ScheduleError {
21     repr: Repr,
22 }
23 
24 impl Debug for ScheduleError {
fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result25     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
26         std::fmt::Debug::fmt(&self.repr, f)
27     }
28 }
29 
30 impl Display for ScheduleError {
fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result31     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
32         match self.repr {
33             Repr::Simple(kind) => write!(f, "{}", kind.as_str()),
34             Repr::Custom(ref c) => write!(f, "{:?}: {}", c.kind, c.error),
35         }
36     }
37 }
38 
39 enum Repr {
40     Simple(ErrorKind),
41     Custom(Box<Custom>),
42 }
43 
44 impl Debug for Repr {
fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result45     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
46         match *self {
47             Repr::Simple(kind) => f.debug_tuple("Kind").field(&kind).finish(),
48             Repr::Custom(ref c) => std::fmt::Debug::fmt(&c, f),
49         }
50     }
51 }
52 
53 #[derive(Debug)]
54 struct Custom {
55     kind: ErrorKind,
56     error: Box<dyn std::error::Error + Send + Sync>,
57 }
58 
59 /// All error types that could be returned during execution.
60 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
61 pub enum ErrorKind {
62     /// Task already shut down error
63     TaskShutdown,
64     /// Blocking pool thread spawn error
65     BlockSpawnErr,
66     /// Creating netpollor thread error
67     NetSpawnErr,
68     /// Task already canceled error
69     TaskCanceled,
70     /// Task state invalid
71     TaskStateInvalid,
72     /// Panic during execution error
73     Panic,
74     /// Any other type errors
75     Other,
76 }
77 
78 impl ErrorKind {
as_str(&self) -> &'static str79     pub(crate) fn as_str(&self) -> &'static str {
80         match *self {
81             ErrorKind::TaskShutdown => "task already get shutdown",
82             ErrorKind::BlockSpawnErr => "blocking pool thread initialization failed",
83             ErrorKind::NetSpawnErr => "net poller thread initialization failed",
84             ErrorKind::TaskCanceled => "task already canceled",
85             ErrorKind::TaskStateInvalid => "task state invalid",
86             ErrorKind::Panic => "panic error",
87             ErrorKind::Other => "other error",
88         }
89     }
90 }
91 
92 impl From<ErrorKind> for ScheduleError {
93     /// Turns ErrorKind into ScheduleError
94     ///
95     /// # Examples
96     ///
97     /// ```
98     /// use ylong_runtime::error::{ErrorKind, ScheduleError};
99     ///
100     /// let task_shutdown = ErrorKind::TaskShutdown;
101     /// let error = ScheduleError::from(task_shutdown);
102     /// assert_eq!("task already get shutdown", format!("{}", error));
103     /// ```
from(kind: ErrorKind) -> Self104     fn from(kind: ErrorKind) -> Self {
105         ScheduleError {
106             repr: Repr::Simple(kind),
107         }
108     }
109 }
110 
111 impl ScheduleError {
112     /// User defined error with customized error msg.
113     ///
114     /// # Examples
115     ///
116     /// ```
117     /// use ylong_runtime::error::{ErrorKind, ScheduleError};
118     ///
119     /// // Able to create new error types directly from strings
120     /// let custom_error = ScheduleError::new(ErrorKind::TaskShutdown, "task shutdown");
121     ///
122     /// // It is also possible to create new error types from other error types
123     /// let custom_error2 = ScheduleError::new(ErrorKind::TaskShutdown, custom_error);
124     /// ```
new<E>(kind: ErrorKind, error: E) -> ScheduleError where E: Into<Box<dyn std::error::Error + Send + Sync>>,125     pub fn new<E>(kind: ErrorKind, error: E) -> ScheduleError
126     where
127         E: Into<Box<dyn std::error::Error + Send + Sync>>,
128     {
129         Self::_new(kind, error.into())
130     }
131 
_new(kind: ErrorKind, error: Box<dyn std::error::Error + Send + Sync>) -> ScheduleError132     fn _new(kind: ErrorKind, error: Box<dyn std::error::Error + Send + Sync>) -> ScheduleError {
133         ScheduleError {
134             repr: Repr::Custom(Box::new(Custom { kind, error })),
135         }
136     }
137 
138     /// Gets the interior error msg from user defined error.
139     ///
140     /// # Examples
141     ///
142     /// ```
143     /// use ylong_runtime::error::{ErrorKind, ScheduleError};
144     ///
145     /// fn print_error(err: ScheduleError) {
146     ///     if let Some(inner_err) = err.into_inner() {
147     ///         println!("Inner error: {}", inner_err);
148     ///     } else {
149     ///         println!("No inner error");
150     ///     }
151     /// }
152     ///
153     /// fn main() {
154     ///     print_error(ScheduleError::new(ErrorKind::TaskShutdown, "oh no!"));
155     /// }
156     /// ```
into_inner(self) -> Option<Box<dyn std::error::Error + Send + Sync>>157     pub fn into_inner(self) -> Option<Box<dyn std::error::Error + Send + Sync>> {
158         match self.repr {
159             Repr::Simple(..) => None,
160             Repr::Custom(c) => Some(c.error),
161         }
162     }
163 
164     /// Gets the ErrorKind of the error.
165     ///
166     /// # Examples
167     ///
168     /// ```
169     /// use ylong_runtime::error::{ErrorKind, ScheduleError};
170     ///
171     /// fn print_error(err: ScheduleError) {
172     ///     println!("{:?}", err.kind());
173     /// }
174     ///
175     /// fn main() {
176     ///     print_error(ErrorKind::TaskShutdown.into());
177     ///     print_error(ScheduleError::new(ErrorKind::TaskShutdown, "task shutdown"));
178     /// }
179     /// ```
kind(&self) -> ErrorKind180     pub fn kind(&self) -> ErrorKind {
181         match self.repr {
182             Repr::Simple(kind) => kind,
183             Repr::Custom(ref c) => c.kind,
184         }
185     }
186 }
187 
188 impl From<ScheduleError> for io::Error {
from(e: ScheduleError) -> Self189     fn from(e: ScheduleError) -> Self {
190         io::Error::new(io::ErrorKind::Other, e)
191     }
192 }
193 
194 impl std::error::Error for ScheduleError {}
195 
196 #[cfg(test)]
197 mod test {
198     use crate::error::{ErrorKind, ScheduleError};
199 
200     /// UT test cases for ScheduleError `Debug`
201     ///
202     /// # Brief
203     /// 1. Creating simple errors
204     /// 2. Creating complex errors
205     #[test]
ut_schedule_error_debug()206     fn ut_schedule_error_debug() {
207         let simple_error: ScheduleError = ErrorKind::TaskShutdown.into();
208         let custom_error = ScheduleError::new(ErrorKind::TaskShutdown, "task shutdown");
209 
210         assert_eq!(format!("{simple_error:?}"), "Kind(TaskShutdown)");
211         assert_eq!(
212             format!("{custom_error:?}"),
213             "Custom { kind: TaskShutdown, error: \"task shutdown\" }"
214         );
215     }
216 
217     /// UT test cases for ScheduleError `Display`
218     ///
219     /// # Brief
220     /// 1. Creating simple errors
221     /// 2. Creating complex errors
222     #[test]
ut_schedule_error_display()223     fn ut_schedule_error_display() {
224         let simple_error: ScheduleError = ErrorKind::TaskShutdown.into();
225         let custom_error = ScheduleError::new(ErrorKind::TaskShutdown, "custom task shutdown");
226 
227         assert_eq!(format!("{simple_error}"), "task already get shutdown");
228         assert_eq!(
229             format!("{custom_error}"),
230             "TaskShutdown: custom task shutdown"
231         );
232     }
233 
234     /// UT test cases for ScheduleError::new()
235     ///
236     /// # Brief
237     /// 1. Creating simple errors
238     /// 2. Creating complex errors
239     #[test]
ut_schedule_error_new()240     fn ut_schedule_error_new() {
241         let custom_error_one =
242             ScheduleError::new(ErrorKind::Other, std::sync::mpsc::RecvTimeoutError::Timeout);
243         assert_eq!(
244             format!("{custom_error_one:?}"),
245             "Custom { kind: Other, error: Timeout }"
246         );
247         assert_eq!(
248             format!("{custom_error_one}"),
249             "Other: timed out waiting on channel"
250         );
251 
252         let custom_error_two = ScheduleError::new(ErrorKind::TaskShutdown, "task shutdown");
253         assert_eq!(
254             format!("{custom_error_two:?}"),
255             "Custom { kind: TaskShutdown, error: \"task shutdown\" }"
256         );
257         assert_eq!(format!("{custom_error_two}"), "TaskShutdown: task shutdown");
258     }
259 
260     /// UT test cases for ScheduleError::kind()
261     ///
262     /// # Brief
263     /// 1. Creating simple errors
264     /// 2. Creating complex errors
265     #[test]
ut_schedule_error_kind()266     fn ut_schedule_error_kind() {
267         let simple_error: ScheduleError = ErrorKind::Other.into();
268         let custom_error = ScheduleError::new(ErrorKind::TaskShutdown, "task shutdown");
269 
270         assert_eq!(format!("{:?}", simple_error.kind()), "Other");
271         assert_eq!(format!("{:?}", custom_error.kind()), "TaskShutdown");
272     }
273 
274     /// UT test cases for ScheduleError::into_inner()
275     ///
276     /// # Brief
277     /// 1. Creating simple errors
278     /// 2. Creating complex errors
279     #[test]
ut_schedule_error_into_inner()280     fn ut_schedule_error_into_inner() {
281         let simple_error: ScheduleError = ErrorKind::Other.into();
282         let custom_error = ScheduleError::new(ErrorKind::TaskShutdown, "task shutdown");
283 
284         assert!(simple_error.into_inner().is_none());
285         assert_eq!(
286             format!("{}", custom_error.into_inner().unwrap()),
287             "task shutdown"
288         );
289     }
290 }
291