Skip to main content

task/
error.rs

1use core::{fmt, num::NonZeroU32};
2use internationalization::translate;
3
4pub type Result<T> = core::result::Result<T, Error>;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[repr(u8)]
8pub enum Error {
9    InvalidTaskIdentifier = 1,
10    InvalidSpawnerIdentifier,
11    ThreadNotRegistered,
12    ThreadAlreadyRegistered,
13    FailedToCreateThread,
14    NoThreadForTask,
15    FailedToSpawnThread,
16    InvalidEnvironmentVariable,
17    TooManyTasks,
18    TooManySpawners,
19    AlreadyInitialized,
20    AlreadySet,
21    NotInitialized,
22    NoSpawnerAvailable,
23}
24
25impl fmt::Display for Error {
26    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27        match self {
28            Error::InvalidTaskIdentifier => write!(f, translate!("InvalidTaskIdentifier")),
29            Error::InvalidSpawnerIdentifier => write!(f, translate!("InvalidSpawnerIdentifier")),
30            Error::ThreadNotRegistered => write!(f, translate!("ThreadNotRegistered")),
31            Error::ThreadAlreadyRegistered => write!(f, translate!("ThreadAlreadyRegistered")),
32            Error::FailedToCreateThread => write!(f, translate!("FailedToCreateThread")),
33            Error::NoThreadForTask => write!(f, translate!("NoThreadForTask")),
34            Error::FailedToSpawnThread => write!(f, translate!("FailedToSpawnThread")),
35            Error::InvalidEnvironmentVariable => {
36                write!(f, translate!("InvalidEnvironmentVariable"))
37            }
38            Error::TooManyTasks => write!(f, translate!("TooManyTasks")),
39            Error::TooManySpawners => write!(f, translate!("TooManySpawners")),
40            Error::AlreadyInitialized => write!(f, translate!("AlreadyInitialized")),
41            Error::AlreadySet => write!(f, translate!("AlreadySet")),
42            Error::NotInitialized => write!(f, translate!("NotInitialized")),
43            Error::NoSpawnerAvailable => write!(f, translate!("NoSpawnerAvailable")),
44        }
45    }
46}
47
48impl core::error::Error for Error {}
49
50impl From<Error> for NonZeroU32 {
51    fn from(error: Error) -> Self {
52        unsafe { NonZeroU32::new_unchecked(error as u32) }
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59    use std::format;
60    use std::string::{String, ToString};
61    use std::vec;
62
63    #[test]
64    fn test_error_type_display() {
65        let error = Error::InvalidTaskIdentifier;
66        let display_string = format!("{error}");
67        assert_eq!(display_string, "Invalid task identifier");
68
69        let error = Error::TooManyTasks;
70        let display_string = format!("{error}");
71        assert_eq!(display_string, "Too many tasks");
72    }
73
74    #[test]
75    fn test_error_type_debug() {
76        let error = Error::InvalidSpawnerIdentifier;
77        let debug_string = format!("{error:?}");
78        assert_eq!(debug_string, "InvalidSpawnerIdentifier");
79
80        let error = Error::ThreadNotRegistered;
81        let debug_string = format!("{error:?}");
82        assert_eq!(debug_string, "ThreadNotRegistered");
83    }
84
85    #[test]
86    fn test_error_type_clone() {
87        let error1 = Error::FailedToCreateThread;
88        let error2 = error1.clone();
89
90        assert_eq!(format!("{error1:?}"), format!("{:?}", error2));
91    }
92
93    #[test]
94    fn test_all_error_variants() {
95        let errors = vec![
96            Error::InvalidTaskIdentifier,
97            Error::InvalidSpawnerIdentifier,
98            Error::ThreadNotRegistered,
99            Error::ThreadAlreadyRegistered,
100            Error::FailedToCreateThread,
101            Error::NoThreadForTask,
102            Error::FailedToSpawnThread,
103            Error::InvalidEnvironmentVariable,
104            Error::TooManyTasks,
105            Error::TooManySpawners,
106            Error::AlreadyInitialized,
107            Error::AlreadySet,
108            Error::NotInitialized,
109            Error::NoSpawnerAvailable,
110        ];
111
112        // Test that all variants can be created and formatted
113        for error in errors {
114            let debug_str = format!("{error:?}");
115            let display_str = format!("{error}");
116
117            assert!(!debug_str.is_empty());
118            assert!(!display_str.is_empty());
119        }
120    }
121
122    #[test]
123    fn test_error_to_nonzero_u32_conversion() {
124        let errors_and_expected_values = vec![
125            (Error::InvalidTaskIdentifier, 1u32),
126            (Error::InvalidSpawnerIdentifier, 2u32),
127            (Error::ThreadNotRegistered, 3u32),
128            (Error::ThreadAlreadyRegistered, 4u32),
129            (Error::FailedToCreateThread, 5u32),
130            (Error::NoThreadForTask, 6u32),
131            (Error::FailedToSpawnThread, 7u32),
132            (Error::InvalidEnvironmentVariable, 8u32),
133            (Error::TooManyTasks, 9u32),
134            (Error::TooManySpawners, 10u32),
135            (Error::AlreadyInitialized, 11u32),
136            (Error::AlreadySet, 12u32),
137            (Error::NotInitialized, 13u32),
138            (Error::NoSpawnerAvailable, 14u32),
139        ];
140
141        for (error, expected_value) in errors_and_expected_values {
142            let non_zero: NonZeroU32 = error.into();
143            assert_eq!(non_zero.get(), expected_value);
144        }
145    }
146
147    #[test]
148    fn test_result_type_ok() {
149        let result: Result<i32> = Ok(42);
150        assert!(result.is_ok());
151        if let Ok(value) = result {
152            assert_eq!(value, 42);
153        }
154    }
155
156    #[test]
157    fn test_result_type_err() {
158        let result: Result<i32> = Err(Error::InvalidTaskIdentifier);
159        assert!(result.is_err());
160
161        if let Err(error) = result {
162            assert_eq!(format!("{error:?}"), "InvalidTaskIdentifier");
163        }
164    }
165
166    #[test]
167    fn test_error_in_result_chain() {
168        fn might_fail(should_fail: bool) -> Result<String> {
169            if should_fail {
170                Err(Error::TooManyTasks)
171            } else {
172                Ok("Success".to_string())
173            }
174        }
175
176        let success_result = might_fail(false);
177        assert!(success_result.is_ok());
178        if let Ok(value) = success_result {
179            assert_eq!(value, "Success");
180        }
181
182        let failure_result = might_fail(true);
183        assert!(failure_result.is_err());
184
185        if let Err(error) = failure_result {
186            assert_eq!(format!("{error:?}"), "TooManyTasks");
187        }
188    }
189
190    #[test]
191    fn test_error_propagation() {
192        fn inner_function() -> Result<i32> {
193            Err(Error::NotInitialized)
194        }
195
196        fn outer_function() -> Result<String> {
197            let _value = inner_function()?;
198            Ok("This won't be reached".to_string())
199        }
200
201        let result = outer_function();
202        assert!(result.is_err());
203
204        if let Err(error) = result {
205            assert_eq!(format!("{error:?}"), "NotInitialized");
206        }
207    }
208
209    #[test]
210    fn test_error_size() {
211        // Ensure the error type has a reasonable size
212        assert!(std::mem::size_of::<Error>() <= 8);
213    }
214
215    #[test]
216    fn test_specific_error_scenarios() {
217        // Test environment variable error specifically
218        let env_error = Error::InvalidEnvironmentVariable;
219        let display_str = format!("{env_error}");
220        let non_zero: NonZeroU32 = env_error.into();
221        assert_eq!(non_zero.get(), 8u32);
222        assert_eq!(display_str, "Invalid environment variable");
223
224        // Test task-related errors
225        let task_error = Error::InvalidTaskIdentifier;
226        assert_eq!(format!("{task_error}"), "Invalid task identifier");
227
228        let spawner_error = Error::InvalidSpawnerIdentifier;
229        assert_eq!(format!("{spawner_error}"), "Invalid spawner identifier");
230    }
231}