use crate::wire::WireError;
use std::io;
#[derive(Debug)]
pub enum ReplicaError {
HandshakeRejected,
AckMalformed,
Truncated,
Frame(WireError),
OffsetGap {
expected: u64,
got: u64,
},
UnexpectedInSnapshot,
SnapshotInProgress,
Io(io::Error),
}
impl std::fmt::Display for ReplicaError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::HandshakeRejected => write!(f, "primary rejected replication handshake"),
Self::AckMalformed => write!(f, "primary sent malformed +ACK"),
Self::Truncated => write!(f, "replication stream truncated by peer"),
Self::Frame(e) => write!(f, "replication frame decode error: {e}"),
Self::OffsetGap { expected, got } => {
write!(f, "replication offset gap: expected {expected}, got {got}")
}
Self::UnexpectedInSnapshot => {
write!(f, "primary sent non-chunk bytes mid-snapshot")
}
Self::SnapshotInProgress => {
write!(f, "snapshot in progress; use next_event() to consume")
}
Self::Io(e) => write!(f, "replication socket I/O error: {e}"),
}
}
}
impl std::error::Error for ReplicaError {}
impl From<io::Error> for ReplicaError {
fn from(e: io::Error) -> Self {
ReplicaError::Io(e)
}
}
impl From<WireError> for ReplicaError {
fn from(e: WireError) -> Self {
match e {
WireError::Truncated => ReplicaError::Truncated,
other => ReplicaError::Frame(other),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_io_error_wraps_into_io_variant() {
let e: ReplicaError = io::Error::new(io::ErrorKind::ConnectionRefused, "x").into();
assert!(matches!(e, ReplicaError::Io(_)));
}
#[test]
fn from_wire_error_truncated_maps_to_truncated() {
let e: ReplicaError = WireError::Truncated.into();
assert!(matches!(e, ReplicaError::Truncated));
}
#[test]
fn from_wire_error_other_maps_to_frame() {
let e: ReplicaError = WireError::BadEnvelope.into();
assert!(matches!(e, ReplicaError::Frame(_)));
}
}