Skip to main content

net_mux/
error.rs

1//! Error and result types.
2
3use std::io;
4
5use thiserror::Error;
6
7/// Crate-wide `Result` alias.
8pub type Result<T> = std::result::Result<T, Error>;
9
10/// Top-level error type.
11#[derive(Debug, Error)]
12#[non_exhaustive]
13pub enum Error {
14    /// The session is closed and no further operations can be performed.
15    #[error("session is closed")]
16    SessionClosed,
17
18    /// The remote peer sent a `GoAway` frame and is no longer accepting new
19    /// streams.
20    #[error("remote sent GoAway: {0}")]
21    GoAway(ErrorCode),
22
23    /// The peer reset the stream.
24    #[error("stream {0} was reset by peer")]
25    StreamReset(u32),
26
27    /// `Config::max_streams` would be exceeded.
28    #[error("too many concurrent streams (limit {0})")]
29    TooManyStreams(usize),
30
31    /// An operation timed out.
32    #[error("operation timed out")]
33    Timeout,
34
35    /// Wire-format violation while decoding a frame.
36    #[error("protocol error: {0}")]
37    Protocol(&'static str),
38
39    /// Underlying I/O failure.
40    #[error("I/O error: {0}")]
41    Io(#[from] io::Error),
42}
43
44impl From<Error> for io::Error {
45    fn from(err: Error) -> io::Error {
46        match err {
47            Error::Io(e) => e,
48            Error::SessionClosed | Error::GoAway(_) => {
49                io::Error::new(io::ErrorKind::NotConnected, err)
50            }
51            Error::StreamReset(_) => io::Error::new(io::ErrorKind::ConnectionReset, err),
52            Error::Timeout => io::Error::new(io::ErrorKind::TimedOut, err),
53            Error::Protocol(_) => io::Error::new(io::ErrorKind::InvalidData, err),
54            Error::TooManyStreams(_) => io::Error::other(err),
55        }
56    }
57}
58
59/// Wire-level error code, transmitted in `GoAway` frames as a `u32`.
60///
61/// Unknown codes coming from the peer are preserved as [`ErrorCode::Unknown`]
62/// so applications can still observe them.
63#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
64#[non_exhaustive]
65pub enum ErrorCode {
66    /// Graceful shutdown initiated locally or remotely.
67    Normal,
68    /// Wire-format / framing violation.
69    ProtocolError,
70    /// Internal bug in either side.
71    InternalError,
72    /// Peer violated flow control (e.g. sent more bytes than advertised).
73    FlowControlError,
74    /// Maximum concurrent streams would be exceeded.
75    StreamLimit,
76    /// Protocol version mismatch.
77    InvalidVersion,
78    /// Idle / keepalive timeout fired.
79    Timeout,
80    /// Code not recognised by this version of the library.
81    Unknown(u32),
82}
83
84impl ErrorCode {
85    /// Encode the variant as the raw `u32` carried on the wire.
86    pub const fn as_u32(self) -> u32 {
87        match self {
88            ErrorCode::Normal => 0,
89            ErrorCode::ProtocolError => 1,
90            ErrorCode::InternalError => 2,
91            ErrorCode::FlowControlError => 3,
92            ErrorCode::StreamLimit => 4,
93            ErrorCode::InvalidVersion => 5,
94            ErrorCode::Timeout => 6,
95            ErrorCode::Unknown(v) => v,
96        }
97    }
98}
99
100impl From<u32> for ErrorCode {
101    fn from(v: u32) -> Self {
102        match v {
103            0 => ErrorCode::Normal,
104            1 => ErrorCode::ProtocolError,
105            2 => ErrorCode::InternalError,
106            3 => ErrorCode::FlowControlError,
107            4 => ErrorCode::StreamLimit,
108            5 => ErrorCode::InvalidVersion,
109            6 => ErrorCode::Timeout,
110            other => ErrorCode::Unknown(other),
111        }
112    }
113}
114
115impl std::fmt::Display for ErrorCode {
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        match self {
118            ErrorCode::Normal => f.write_str("normal"),
119            ErrorCode::ProtocolError => f.write_str("protocol error"),
120            ErrorCode::InternalError => f.write_str("internal error"),
121            ErrorCode::FlowControlError => f.write_str("flow control error"),
122            ErrorCode::StreamLimit => f.write_str("stream limit"),
123            ErrorCode::InvalidVersion => f.write_str("invalid version"),
124            ErrorCode::Timeout => f.write_str("timeout"),
125            ErrorCode::Unknown(v) => write!(f, "unknown error code {v}"),
126        }
127    }
128}