Skip to main content

beyond_resp/
error.rs

1use thiserror::Error;
2
3#[allow(dead_code)]
4#[derive(Debug, Error)]
5#[must_use = "errors must be handled or explicitly ignored with `let _ =`"]
6pub enum RespError {
7    #[error("incomplete frame")]
8    Incomplete,
9
10    #[error("unknown type byte: 0x{byte:02x}")]
11    InvalidTypeByte { byte: u8 },
12
13    #[error("invalid integer")]
14    InvalidInteger,
15
16    #[error("invalid double")]
17    InvalidDouble,
18
19    #[error("invalid length")]
20    InvalidLength,
21
22    #[error("missing CRLF terminator")]
23    MissingCrlf,
24
25    #[error("verbatim string encoding separator missing or too short")]
26    InvalidVerbatim,
27
28    #[error("invalid big number")]
29    InvalidBigNumber,
30
31    #[error("nesting depth limit exceeded")]
32    DepthLimitExceeded,
33
34    #[error("frame exceeds size limit of {limit} bytes")]
35    FrameTooLarge { limit: usize },
36
37    #[error("I/O error")]
38    Io {
39        #[source]
40        source: std::io::Error,
41    },
42}
43
44impl RespError {
45    pub(crate) fn invalid_type(byte: u8) -> Self {
46        Self::InvalidTypeByte { byte }
47    }
48
49    pub(crate) fn too_large(limit: usize) -> Self {
50        Self::FrameTooLarge { limit }
51    }
52}
53
54impl From<std::io::Error> for RespError {
55    fn from(source: std::io::Error) -> Self {
56        Self::Io { source }
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63    use std::io;
64
65    #[test]
66    fn io_error_converts_to_resp_error() {
67        let io_err = io::Error::new(io::ErrorKind::BrokenPipe, "pipe closed");
68        let resp_err: RespError = io_err.into();
69        assert!(matches!(resp_err, RespError::Io { .. }));
70        assert!(resp_err.to_string().contains("I/O error"));
71    }
72}