mtcp_rs/
error.rs

1/*
2 * mtcp - TcpListener/TcpStream *with* timeout/cancellation support
3 * This is free and unencumbered software released into the public domain.
4 */
5use std::error::Error;
6use std::fmt::{Display, Debug, Formatter};
7use std::io::{ErrorKind, Error as IoError};
8
9/// The error type for **mtcp** I/O operations
10/// 
11/// **mtcp** I/O operations return a [`std::io::Result`](std::io::Result),
12/// which will contain an [`std::io::Error`](std::io::Error) in case of
13/// failure. For ***mtcp**-specific* errors, the returned `std::io::Error`
14/// contains the suitable variant of `mtcp_rs::TcpError` as its "inner" error.
15///
16/// Errors from the **`mio`** layer are passed through "as-is"; do **not**
17/// expect that an "inner" `mtcp_rs::TcpError` is always available!
18
19pub enum TcpError {
20    /// Indicates that the socket operation was *cancelled* before completion.
21    /// Data may have been read or written partially!
22    Cancelled,
23    /// Indicates that the socket operation encountered a time-out. Data may
24    /// have been read or written partially!
25    TimedOut,
26    /// Indicates that the socket operation finished (usually because the
27    /// stream was closed) before all data could be read or written.
28    Incomplete,
29    /// Indicates that the socket *read* operation was aborted, because the
30    /// length of the data would have exceeded the specified limit.
31    TooBig,
32    /// Indicates that the socket operation has failed. More detailed
33    /// information is available via the wrapped [`io::Error`](std::io::Error).
34    Failed(IoError)
35}
36
37impl Error for TcpError { }
38
39impl Debug for TcpError {
40    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
41        match self {
42            Self::Cancelled => write!(f, "TcpError::Cancelled"),
43            Self::TimedOut => write!(f, "TcpError::TimedOut"),
44            Self::Incomplete => write!(f, "TcpError::Incomplete"),
45            Self::TooBig => write!(f, "TcpError::TooBig"),
46            Self::Failed(error) => write!(f, "TcpError::Failed({error})"),
47        }
48    }
49}
50
51impl Display for TcpError {
52    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
53        match self {
54            Self::Cancelled => write!(f, "The TCP socket operation was cancelled!"),
55            Self::TimedOut => write!(f, "The TCP socket operation timed out!"),
56            Self::Incomplete => write!(f, "The TCP socket operation is incomplete!"),
57            Self::TooBig => write!(f, "The TCP socket operation aborted, data is too big!"),
58            Self::Failed(error) => write!(f, "{error}"),
59        }
60    }
61}
62
63impl From<TcpError> for IoError {
64    fn from(value: TcpError) -> Self {
65        match value {
66            TcpError::Failed(error) => error,
67            other => IoError::new(ErrorKind::Other, other),
68        }
69    }
70}
71
72impl From<IoError> for TcpError {
73    fn from(value: IoError) -> Self {
74        match try_downcast::<TcpError>(value) {
75            Ok(error) => error,
76            Err(other) => TcpError::Failed(other),
77        }
78    }
79}
80
81fn try_downcast<T: Error + 'static>(error: IoError) -> Result<T, IoError> {
82    match error.get_ref().map(|inner| inner.is::<T>()) {
83        Some(true) => Ok(*error.into_inner().unwrap().downcast::<T>().unwrap()),
84        _ => Err(error),
85    }
86}