1use std::io;
4use thiserror::Error;
5
6pub type Result<T> = std::result::Result<T, Error>;
8
9#[derive(Error, Debug)]
11pub enum Error {
12 #[error("I/O error: {0}")]
14 Io(#[from] io::Error),
15
16 #[error("TLS error: {0}")]
18 Tls(String),
19
20 #[error("NTS key exchange failed: {0}")]
22 KeyExchange(String),
23
24 #[error("NTP protocol error: {0}")]
26 Protocol(String),
27
28 #[error("Invalid server response: {0}")]
30 InvalidResponse(String),
31
32 #[error("Operation timed out")]
34 Timeout,
35
36 #[error("Invalid configuration: {0}")]
38 InvalidConfig(String),
39
40 #[error("Server unreachable: {0}")]
42 ServerUnavailable(String),
43
44 #[error("Authentication failed: {0}")]
46 AuthenticationFailed(String),
47
48 #[error("Missing NTS cookie")]
50 MissingNtsCookie,
51
52 #[error("Missing NTS authenticator")]
54 MissingAuthenticator,
55
56 #[error("AEAD verification failed: {0}")]
58 AeadVerificationFailed(String),
59
60 #[error("Malformed NTS extension fields: {0}")]
62 MalformedNtsExtension(String),
63
64 #[error("No NTS cookies returned by server")]
66 NoCookiesReturned,
67
68 #[error("{0}")]
70 Other(String),
71}
72
73impl From<rustls::Error> for Error {
74 fn from(err: rustls::Error) -> Self {
75 Error::Tls(err.to_string())
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn test_error_display() {
85 let err = Error::Timeout;
86 assert_eq!(err.to_string(), "Operation timed out");
87
88 let err = Error::InvalidConfig("test error".to_string());
89 assert_eq!(err.to_string(), "Invalid configuration: test error");
90
91 let err = Error::ServerUnavailable("server down".to_string());
92 assert_eq!(err.to_string(), "Server unreachable: server down");
93
94 let err = Error::MissingNtsCookie;
95 assert_eq!(err.to_string(), "Missing NTS cookie");
96
97 let err = Error::MissingAuthenticator;
98 assert_eq!(err.to_string(), "Missing NTS authenticator");
99
100 let err = Error::AeadVerificationFailed("bad tag".to_string());
101 assert_eq!(err.to_string(), "AEAD verification failed: bad tag");
102
103 let err = Error::MalformedNtsExtension("bad field".to_string());
104 assert_eq!(err.to_string(), "Malformed NTS extension fields: bad field");
105
106 let err = Error::NoCookiesReturned;
107 assert_eq!(err.to_string(), "No NTS cookies returned by server");
108 }
109
110 #[test]
111 fn test_io_error_conversion() {
112 let io_err = io::Error::new(io::ErrorKind::ConnectionRefused, "refused");
113 let err: Error = io_err.into();
114 assert!(matches!(err, Error::Io(_)));
115 }
116
117 #[test]
118 fn test_error_is_send_sync() {
119 fn assert_send_sync<T: Send + Sync>() {}
120 assert_send_sync::<Error>();
121 }
122}