macro_rules! read_exact {
($stream: expr, $array: expr) => {{
let mut x = $array;
$stream.read_exact(&mut x).await.map(|_| x)
}};
}
pub(crate) use read_exact;
use crate::rfc1928::ReplyError;
use std::io;
#[derive(thiserror::Error, Debug)]
pub enum ConnectError {
#[error("Connection timed out")]
ConnectionTimeout,
#[error("Connection refused: {0}")]
ConnectionRefused(#[source] io::Error),
#[error("Connection aborted: {0}")]
ConnectionAborted(#[source] io::Error),
#[error("Connection reset: {0}")]
ConnectionReset(#[source] io::Error),
#[error("Not connected: {0}")]
NotConnected(#[source] io::Error),
#[error("Other i/o error: {0}")]
Other(#[source] io::Error),
}
impl ConnectError {
pub fn to_reply_error(&self) -> ReplyError {
match self {
ConnectError::ConnectionTimeout => ReplyError::ConnectionTimeout,
ConnectError::ConnectionRefused(_) => ReplyError::ConnectionRefused,
ConnectError::ConnectionAborted(_) | ConnectError::ConnectionReset(_) => {
ReplyError::ConnectionNotAllowed
}
ConnectError::NotConnected(_) => ReplyError::NetworkUnreachable,
ConnectError::Other(_) => ReplyError::GeneralFailure,
}
}
}
#[cfg(test)]
mod tests {
use super::ConnectError;
use crate::rfc1928::ReplyError;
use std::io::ErrorKind;
#[test]
fn to_reply_error_mapping() {
assert!(matches!(
ConnectError::ConnectionTimeout.to_reply_error(),
ReplyError::ConnectionTimeout
));
assert!(matches!(
ConnectError::ConnectionRefused(ErrorKind::ConnectionRefused.into()).to_reply_error(),
ReplyError::ConnectionRefused
));
assert!(matches!(
ConnectError::ConnectionAborted(ErrorKind::ConnectionAborted.into()).to_reply_error(),
ReplyError::ConnectionNotAllowed
));
assert!(matches!(
ConnectError::ConnectionReset(ErrorKind::ConnectionReset.into()).to_reply_error(),
ReplyError::ConnectionNotAllowed
));
assert!(matches!(
ConnectError::NotConnected(ErrorKind::NotConnected.into()).to_reply_error(),
ReplyError::NetworkUnreachable
));
assert!(matches!(
ConnectError::Other(ErrorKind::Other.into()).to_reply_error(),
ReplyError::GeneralFailure
));
}
}