1use std::time::Duration;
2use thiserror::Error;
3
4#[derive(Debug, Error)]
9#[non_exhaustive]
10pub enum HexeractError {
11 #[error("no handler registered for `{command_type}`")]
13 HandlerNotFound {
14 command_type: &'static str,
16 },
17
18 #[error("handler failed: {source}")]
20 HandlerFailed {
21 #[source]
23 source: Box<dyn std::error::Error + Send + Sync>,
24 },
25
26 #[error("dispatch timed out after {elapsed:?}")]
28 Timeout {
29 elapsed: Duration,
31 },
32
33 #[error("dispatch error: {0}")]
35 Dispatch(String),
36}
37
38impl HexeractError {
39 pub fn handler_failed(source: impl std::error::Error + Send + Sync + 'static) -> Self {
41 Self::HandlerFailed {
42 source: Box::new(source),
43 }
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50
51 #[test]
52 fn handler_not_found_display() {
53 let err = HexeractError::HandlerNotFound {
54 command_type: "RegisterUser",
55 };
56 assert_eq!(err.to_string(), "no handler registered for `RegisterUser`");
57 }
58
59 #[test]
60 fn timeout_display_shows_duration() {
61 let err = HexeractError::Timeout {
62 elapsed: Duration::from_secs(5),
63 };
64 assert!(err.to_string().contains("5s"));
65 }
66
67 #[test]
68 fn handler_failed_preserves_source() {
69 let original = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
70 let err = HexeractError::handler_failed(original);
71 assert!(err.to_string().contains("handler failed"));
72 assert!(std::error::Error::source(&err).is_some());
73 }
74}