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