use thiserror::Error;
use super::types::InstanceId;
#[derive(Debug, Error)]
pub enum SyncError {
#[error("Sync transport error: {0}")]
Transport(String),
#[error("Sync handshake failed: {0}")]
Handshake(String),
#[error("Sync serialization error: {0}")]
Serialization(String),
#[error("Sync operation timed out")]
Timeout,
#[error("Connection to sync peer lost")]
ConnectionLost,
#[error("Sync protocol version mismatch: local v{local}, remote v{remote}")]
ProtocolVersion {
local: u32,
remote: u32,
},
#[error("Invalid sync payload: {0}")]
InvalidPayload(String),
#[error("No sync cursor found for instance {instance}")]
CursorNotFound {
instance: InstanceId,
},
#[error("Sync system is shutting down")]
Shutdown,
}
impl SyncError {
pub fn transport(msg: impl Into<String>) -> Self {
Self::Transport(msg.into())
}
pub fn handshake(msg: impl Into<String>) -> Self {
Self::Handshake(msg.into())
}
pub fn serialization(msg: impl Into<String>) -> Self {
Self::Serialization(msg.into())
}
pub fn invalid_payload(msg: impl Into<String>) -> Self {
Self::InvalidPayload(msg.into())
}
pub fn is_transport(&self) -> bool {
matches!(self, Self::Transport(_))
}
pub fn is_timeout(&self) -> bool {
matches!(self, Self::Timeout)
}
pub fn is_connection_lost(&self) -> bool {
matches!(self, Self::ConnectionLost)
}
pub fn is_shutdown(&self) -> bool {
matches!(self, Self::Shutdown)
}
}
impl From<bincode::Error> for SyncError {
fn from(err: bincode::Error) -> Self {
SyncError::Serialization(err.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sync_error_display() {
let err = SyncError::transport("connection refused");
assert_eq!(err.to_string(), "Sync transport error: connection refused");
}
#[test]
fn test_protocol_version_display() {
let err = SyncError::ProtocolVersion {
local: 1,
remote: 2,
};
assert_eq!(
err.to_string(),
"Sync protocol version mismatch: local v1, remote v2"
);
}
#[test]
fn test_sync_error_is_checks() {
assert!(SyncError::transport("x").is_transport());
assert!(SyncError::Timeout.is_timeout());
assert!(SyncError::ConnectionLost.is_connection_lost());
assert!(SyncError::Shutdown.is_shutdown());
}
#[test]
fn test_bincode_error_conversion() {
let bad_bytes = vec![0u8; 1]; let bincode_err = bincode::deserialize::<(u64, u64)>(&bad_bytes).unwrap_err();
let sync_err: SyncError = bincode_err.into();
assert!(matches!(sync_err, SyncError::Serialization(_)));
}
}