nanonis_rs/error.rs
1use thiserror::Error;
2
3/// Error types for Nanonis communication.
4///
5/// This enum represents the four categories of errors that can occur:
6/// - [`Io`](NanonisError::Io) - Network and I/O errors
7/// - [`Timeout`](NanonisError::Timeout) - Connection or operation timeouts
8/// - [`Protocol`](NanonisError::Protocol) - Binary protocol parsing/validation errors
9/// - [`Server`](NanonisError::Server) - Errors returned by the Nanonis server
10#[derive(Error, Debug)]
11pub enum NanonisError {
12 /// IO error with context describing what operation failed.
13 ///
14 /// # Example
15 /// ```
16 /// use nanonis_rs::NanonisError;
17 ///
18 /// let io_err = std::io::Error::new(std::io::ErrorKind::ConnectionRefused, "refused");
19 /// let err = NanonisError::Io {
20 /// source: io_err,
21 /// context: "connecting to server".to_string(),
22 /// };
23 /// assert!(err.to_string().contains("connecting to server"));
24 /// ```
25 #[error("IO error: {context}")]
26 Io {
27 #[source]
28 source: std::io::Error,
29 context: String,
30 },
31
32 /// Connection or operation timeout.
33 ///
34 /// Contains an optional description of what timed out.
35 ///
36 /// # Example
37 /// ```
38 /// use nanonis_rs::NanonisError;
39 ///
40 /// let err = NanonisError::Timeout("waiting for scan to complete".to_string());
41 /// assert!(err.to_string().contains("scan"));
42 /// ```
43 #[error("Timeout{}", if .0.is_empty() { String::new() } else { format!(": {}", .0) })]
44 Timeout(String),
45
46 /// Protocol error during parsing, validation, or type conversion.
47 ///
48 /// This covers all errors related to the binary protocol:
49 /// - Unexpected response formats
50 /// - Type mismatches in received data
51 /// - Invalid command parameters
52 /// - Serialization failures
53 ///
54 /// # Example
55 /// ```
56 /// use nanonis_rs::NanonisError;
57 ///
58 /// let err = NanonisError::Protocol("Expected f32, got i32".to_string());
59 /// assert!(err.to_string().contains("Expected f32"));
60 /// ```
61 #[error("Protocol error: {0}")]
62 Protocol(String),
63
64 /// Error returned by the Nanonis server.
65 ///
66 /// The server returns an error code and message when a command fails.
67 ///
68 /// # Example
69 /// ```
70 /// use nanonis_rs::NanonisError;
71 ///
72 /// let err = NanonisError::Server {
73 /// code: -1,
74 /// message: "Invalid parameter".to_string(),
75 /// };
76 /// assert!(err.is_server_error());
77 /// assert_eq!(err.error_code(), Some(-1));
78 /// ```
79 #[error("Server error: {message} (code: {code})")]
80 Server { code: i32, message: String },
81}
82
83impl NanonisError {
84 /// Check if this is a server-side error.
85 pub fn is_server_error(&self) -> bool {
86 matches!(self, NanonisError::Server { .. })
87 }
88
89 /// Get error code if this is a server error.
90 pub fn error_code(&self) -> Option<i32> {
91 match self {
92 NanonisError::Server { code, .. } => Some(*code),
93 _ => None,
94 }
95 }
96
97 /// Check if this is a timeout error.
98 pub fn is_timeout(&self) -> bool {
99 matches!(self, NanonisError::Timeout(_))
100 }
101
102 /// Check if this is an I/O error.
103 pub fn is_io(&self) -> bool {
104 matches!(self, NanonisError::Io { .. })
105 }
106
107 /// Check if this is a protocol error.
108 pub fn is_protocol(&self) -> bool {
109 matches!(self, NanonisError::Protocol(_))
110 }
111}
112
113// Allow conversion from std::io::Error
114impl From<std::io::Error> for NanonisError {
115 fn from(error: std::io::Error) -> Self {
116 NanonisError::Io {
117 source: error,
118 context: "IO operation failed".to_string(),
119 }
120 }
121}
122
123// Allow conversion from serde_json::Error
124impl From<serde_json::Error> for NanonisError {
125 fn from(error: serde_json::Error) -> Self {
126 NanonisError::Protocol(format!("JSON serialization error: {error}"))
127 }
128}