1use thiserror::Error;
8
9use super::types::InstanceId;
10
11#[derive(Debug, Error)]
16pub enum SyncError {
17 #[error("Sync transport error: {0}")]
19 Transport(String),
20
21 #[error("Sync handshake failed: {0}")]
23 Handshake(String),
24
25 #[error("Sync serialization error: {0}")]
27 Serialization(String),
28
29 #[error("Sync operation timed out")]
31 Timeout,
32
33 #[error("Connection to sync peer lost")]
35 ConnectionLost,
36
37 #[error("Sync protocol version mismatch: local v{local}, remote v{remote}")]
39 ProtocolVersion {
40 local: u32,
42 remote: u32,
44 },
45
46 #[error("Invalid sync payload: {0}")]
48 InvalidPayload(String),
49
50 #[error("No sync cursor found for instance {instance}")]
52 CursorNotFound {
53 instance: InstanceId,
55 },
56
57 #[error("Sync system is shutting down")]
59 Shutdown,
60}
61
62impl SyncError {
63 pub fn transport(msg: impl Into<String>) -> Self {
65 Self::Transport(msg.into())
66 }
67
68 pub fn handshake(msg: impl Into<String>) -> Self {
70 Self::Handshake(msg.into())
71 }
72
73 pub fn serialization(msg: impl Into<String>) -> Self {
75 Self::Serialization(msg.into())
76 }
77
78 pub fn invalid_payload(msg: impl Into<String>) -> Self {
80 Self::InvalidPayload(msg.into())
81 }
82
83 pub fn is_transport(&self) -> bool {
85 matches!(self, Self::Transport(_))
86 }
87
88 pub fn is_timeout(&self) -> bool {
90 matches!(self, Self::Timeout)
91 }
92
93 pub fn is_connection_lost(&self) -> bool {
95 matches!(self, Self::ConnectionLost)
96 }
97
98 pub fn is_shutdown(&self) -> bool {
100 matches!(self, Self::Shutdown)
101 }
102}
103
104impl From<bincode::Error> for SyncError {
105 fn from(err: bincode::Error) -> Self {
106 SyncError::Serialization(err.to_string())
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn test_sync_error_display() {
116 let err = SyncError::transport("connection refused");
117 assert_eq!(err.to_string(), "Sync transport error: connection refused");
118 }
119
120 #[test]
121 fn test_protocol_version_display() {
122 let err = SyncError::ProtocolVersion {
123 local: 1,
124 remote: 2,
125 };
126 assert_eq!(
127 err.to_string(),
128 "Sync protocol version mismatch: local v1, remote v2"
129 );
130 }
131
132 #[test]
133 fn test_sync_error_is_checks() {
134 assert!(SyncError::transport("x").is_transport());
135 assert!(SyncError::Timeout.is_timeout());
136 assert!(SyncError::ConnectionLost.is_connection_lost());
137 assert!(SyncError::Shutdown.is_shutdown());
138 }
139
140 #[test]
141 fn test_bincode_error_conversion() {
142 let bad_bytes = vec![0u8; 1]; let bincode_err = bincode::deserialize::<(u64, u64)>(&bad_bytes).unwrap_err();
145 let sync_err: SyncError = bincode_err.into();
146 assert!(matches!(sync_err, SyncError::Serialization(_)));
147 }
148}