Skip to main content

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}