interface_rs/
error.rs

1use crate::interface::FamilyParseError;
2use std::error::Error;
3use std::fmt;
4use std::io;
5
6/// The main error type for the `NetworkInterfaces` library.
7///
8/// This enum encapsulates all possible errors that can occur within the library.
9#[derive(Debug)]
10pub enum NetworkInterfacesError {
11    /// An I/O error occurred.
12    Io(io::Error),
13    /// An error occurred while parsing the interfaces file.
14    Parser(ParserError),
15    /// An error occurred while parsing the `Family` enum.
16    FamilyParse(FamilyParseError),
17    /// The interfaces file has been modified on disk since it was last loaded.
18    FileModified,
19    /// A catch-all for other errors.
20    Other(String),
21}
22
23impl fmt::Display for NetworkInterfacesError {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        match self {
26            NetworkInterfacesError::Io(err) => write!(f, "I/O error: {}", err),
27            NetworkInterfacesError::Parser(err) => write!(f, "Parser error: {}", err),
28            NetworkInterfacesError::FamilyParse(err) => write!(f, "Family parse error: {}", err),
29            NetworkInterfacesError::FileModified => write!(
30                f,
31                "The interfaces file has been modified on disk since it was last loaded."
32            ),
33            NetworkInterfacesError::Other(msg) => write!(f, "Error: {}", msg),
34        }
35    }
36}
37
38impl Error for NetworkInterfacesError {
39    fn source(&self) -> Option<&(dyn Error + 'static)> {
40        match self {
41            NetworkInterfacesError::Io(err) => Some(err),
42            NetworkInterfacesError::Parser(err) => Some(err),
43            NetworkInterfacesError::FamilyParse(err) => Some(err),
44            NetworkInterfacesError::FileModified => None,
45            NetworkInterfacesError::Other(_) => None,
46        }
47    }
48}
49
50impl From<io::Error> for NetworkInterfacesError {
51    fn from(err: io::Error) -> Self {
52        NetworkInterfacesError::Io(err)
53    }
54}
55
56impl From<ParserError> for NetworkInterfacesError {
57    fn from(err: ParserError) -> Self {
58        NetworkInterfacesError::Parser(err)
59    }
60}
61
62impl From<FamilyParseError> for NetworkInterfacesError {
63    fn from(err: FamilyParseError) -> Self {
64        NetworkInterfacesError::FamilyParse(err)
65    }
66}
67
68/// Represents errors that can occur during parsing of the interfaces file.
69#[derive(Debug, Clone)]
70pub struct ParserError {
71    /// A message describing the parsing error.
72    pub message: String,
73    /// Optional line number where the error occurred.
74    pub line: Option<usize>,
75}
76
77impl ParserError {
78    /// Creates a new `ParserError` with a message and line number.
79    pub fn new(message: impl Into<String>, line: usize) -> Self {
80        Self {
81            message: message.into(),
82            line: Some(line),
83        }
84    }
85
86    /// Creates a new `ParserError` with only a message (no line number).
87    pub fn message(message: impl Into<String>) -> Self {
88        Self {
89            message: message.into(),
90            line: None,
91        }
92    }
93}
94
95impl fmt::Display for ParserError {
96    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97        if let Some(line) = self.line {
98            write!(f, "Parser error on line {}: {}", line, self.message)
99        } else {
100            write!(f, "Parser error: {}", self.message)
101        }
102    }
103}
104
105impl Error for ParserError {}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110
111    #[test]
112    fn test_parser_error_new() {
113        let err = ParserError::new("test error", 42);
114        assert_eq!(err.message, "test error");
115        assert_eq!(err.line, Some(42));
116        assert_eq!(err.to_string(), "Parser error on line 42: test error");
117    }
118
119    #[test]
120    fn test_parser_error_message() {
121        let err = ParserError::message("test error");
122        assert_eq!(err.message, "test error");
123        assert_eq!(err.line, None);
124        assert_eq!(err.to_string(), "Parser error: test error");
125    }
126
127    #[test]
128    fn test_network_interfaces_error_display() {
129        let io_err = NetworkInterfacesError::Io(io::Error::new(io::ErrorKind::NotFound, "file not found"));
130        assert!(io_err.to_string().contains("I/O error"));
131
132        let parser_err = NetworkInterfacesError::Parser(ParserError::new("bad syntax", 10));
133        assert!(parser_err.to_string().contains("Parser error"));
134
135        let file_mod = NetworkInterfacesError::FileModified;
136        assert!(file_mod.to_string().contains("modified on disk"));
137
138        let other = NetworkInterfacesError::Other("custom error".to_string());
139        assert!(other.to_string().contains("custom error"));
140    }
141
142    #[test]
143    fn test_error_conversions() {
144        let io_err = io::Error::new(io::ErrorKind::NotFound, "not found");
145        let converted: NetworkInterfacesError = io_err.into();
146        assert!(matches!(converted, NetworkInterfacesError::Io(_)));
147
148        let parser_err = ParserError::new("test", 1);
149        let converted: NetworkInterfacesError = parser_err.into();
150        assert!(matches!(converted, NetworkInterfacesError::Parser(_)));
151    }
152}