use std::fmt;
#[derive(Debug)]
pub struct Error {
source: Option<Box<dyn std::error::Error + Send + Sync>>,
kind: ErrorKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ErrorKind {
BencodeInvalidSyntax,
BencodeInvalidInteger,
BencodeUnexpectedEof,
BencodeIntegerOverflow,
MetainfoMissingField,
MetainfoInvalidField,
MetainfoInvalidPieces,
PeerInvalidHandshake,
PeerInvalidMessage,
PeerConnectionClosed,
PeerInvalidExtendedMessage,
PeerInvalidPexMessage,
TrackerInvalidResponse,
TrackerRequestFailed,
TrackerProtocolError,
Io,
InvalidInput,
Protocol,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.kind {
ErrorKind::BencodeInvalidSyntax => write!(f, "invalid bencode syntax"),
ErrorKind::BencodeInvalidInteger => write!(f, "invalid bencode integer"),
ErrorKind::BencodeUnexpectedEof => write!(f, "unexpected end of bencode data"),
ErrorKind::BencodeIntegerOverflow => write!(f, "bencode integer overflow"),
ErrorKind::MetainfoMissingField => write!(f, "missing required metainfo field"),
ErrorKind::MetainfoInvalidField => write!(f, "invalid metainfo field"),
ErrorKind::MetainfoInvalidPieces => write!(f, "invalid pieces length in metainfo"),
ErrorKind::PeerInvalidHandshake => write!(f, "invalid peer handshake"),
ErrorKind::PeerInvalidMessage => write!(f, "invalid peer message"),
ErrorKind::PeerConnectionClosed => write!(f, "peer connection closed"),
ErrorKind::PeerInvalidExtendedMessage => write!(f, "invalid extended peer message"),
ErrorKind::PeerInvalidPexMessage => write!(f, "invalid PEX message"),
ErrorKind::TrackerInvalidResponse => write!(f, "invalid tracker response"),
ErrorKind::TrackerRequestFailed => write!(f, "tracker request failed"),
ErrorKind::TrackerProtocolError => write!(f, "tracker protocol error"),
ErrorKind::Io => write!(f, "I/O error"),
ErrorKind::InvalidInput => write!(f, "invalid input"),
ErrorKind::Protocol => write!(f, "protocol error"),
}?;
if let Some(ref source) = self.source {
write!(f, ": {source}")?;
}
Ok(())
}
}
impl fmt::Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ErrorKind::BencodeInvalidSyntax => write!(f, "BencodeInvalidSyntax"),
ErrorKind::BencodeInvalidInteger => write!(f, "BencodeInvalidInteger"),
ErrorKind::BencodeUnexpectedEof => write!(f, "BencodeUnexpectedEof"),
ErrorKind::BencodeIntegerOverflow => write!(f, "BencodeIntegerOverflow"),
ErrorKind::MetainfoMissingField => write!(f, "MetainfoMissingField"),
ErrorKind::MetainfoInvalidField => write!(f, "MetainfoInvalidField"),
ErrorKind::MetainfoInvalidPieces => write!(f, "MetainfoInvalidPieces"),
ErrorKind::PeerInvalidHandshake => write!(f, "PeerInvalidHandshake"),
ErrorKind::PeerInvalidMessage => write!(f, "PeerInvalidMessage"),
ErrorKind::PeerConnectionClosed => write!(f, "PeerConnectionClosed"),
ErrorKind::PeerInvalidExtendedMessage => write!(f, "PeerInvalidExtendedMessage"),
ErrorKind::PeerInvalidPexMessage => write!(f, "PeerInvalidPexMessage"),
ErrorKind::TrackerInvalidResponse => write!(f, "TrackerInvalidResponse"),
ErrorKind::TrackerRequestFailed => write!(f, "TrackerRequestFailed"),
ErrorKind::TrackerProtocolError => write!(f, "TrackerProtocolError"),
ErrorKind::Io => write!(f, "Io"),
ErrorKind::InvalidInput => write!(f, "InvalidInput"),
ErrorKind::Protocol => write!(f, "Protocol"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source.as_ref().map(|e| &**e as _)
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Self {
source: Some(Box::new(e)),
kind: ErrorKind::Io,
}
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Self {
Self { kind, source: None }
}
}
impl Error {
pub fn new(kind: ErrorKind) -> Self {
Self { kind, source: None }
}
pub fn with_source(
kind: ErrorKind, source: impl Into<Box<dyn std::error::Error + Send + Sync>>,
) -> Self {
Self {
kind,
source: Some(source.into()),
}
}
pub fn kind(&self) -> ErrorKind {
self.kind
}
pub fn io(source: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
Self::with_source(ErrorKind::Io, source)
}
pub fn peer_closed(source: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
Self::with_source(ErrorKind::PeerConnectionClosed, source)
}
pub fn tracker_failed(source: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
Self::with_source(ErrorKind::TrackerRequestFailed, source)
}
pub fn protocol(source: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
Self::with_source(ErrorKind::Protocol, source)
}
pub fn invalid_input(source: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
Self::with_source(ErrorKind::InvalidInput, source)
}
}