1#[derive(Debug, thiserror::Error)]
14pub enum BackendError {
15 #[error("Initialization failed: {0}")]
17 InitializationError(String),
18
19 #[error("Processing failed: {0}")]
21 ProcessingError(String),
22
23 #[error("Model I/O error: {0}")]
25 ModelError(String),
26
27 #[error("Communication error: {0}")]
29 CommunicationError(String),
30
31 #[error("Invalid input: {0}")]
33 InvalidInput(String),
34
35 #[error(transparent)]
42 Protocol(#[from] ProtocolError),
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
50pub enum ProtocolError {
51 #[error("unexpected IpcMessage variant `{found}`; expected {expected}")]
53 UnexpectedVariant {
54 found: &'static str,
56 expected: &'static str,
58 },
59}
60
61#[cfg(test)]
62mod tests {
63 use super::{BackendError, ProtocolError};
64 use std::error::Error;
65
66 fn protocol() -> ProtocolError {
67 ProtocolError::UnexpectedVariant {
68 found: "Ping",
69 expected: "Spikes",
70 }
71 }
72
73 fn variant_kind(err: &BackendError) -> &'static str {
74 match err {
75 BackendError::InitializationError(_) => "init",
76 BackendError::ProcessingError(_) => "process",
77 BackendError::ModelError(_) => "model",
78 BackendError::CommunicationError(_) => "comm",
79 BackendError::InvalidInput(_) => "input",
80 BackendError::Protocol(_) => "protocol",
81 }
82 }
83
84 #[test]
85 fn backend_error_string_variants_keep_display_source_and_match() {
86 let cases = [
87 (
88 BackendError::InitializationError("model missing".into()),
89 "Initialization failed: model missing",
90 "init",
91 ),
92 (
93 BackendError::ProcessingError("shape mismatch".into()),
94 "Processing failed: shape mismatch",
95 "process",
96 ),
97 (
98 BackendError::ModelError("disk full".into()),
99 "Model I/O error: disk full",
100 "model",
101 ),
102 (
103 BackendError::CommunicationError("timeout".into()),
104 "Communication error: timeout",
105 "comm",
106 ),
107 (
108 BackendError::InvalidInput("empty batch".into()),
109 "Invalid input: empty batch",
110 "input",
111 ),
112 ];
113 for (err, display, kind) in cases {
114 assert_eq!(err.to_string(), display);
115 assert!(err.source().is_none(), "{display}");
116 assert_eq!(variant_kind(&err), kind);
117 }
118 }
119
120 #[test]
121 fn backend_error_protocol_stays_transparent() {
122 let inner = protocol();
123 let err = BackendError::from(inner.clone());
124 assert_eq!(
125 inner.to_string(),
126 "unexpected IpcMessage variant `Ping`; expected Spikes"
127 );
128 assert_eq!(err.to_string(), inner.to_string());
129 assert!(inner.source().is_none());
130 assert!(err.source().is_none());
131 assert!(matches!(
132 err,
133 BackendError::Protocol(ProtocolError::UnexpectedVariant {
134 found: "Ping",
135 expected: "Spikes",
136 })
137 ));
138 assert_eq!(variant_kind(&err), "protocol");
139 }
140}