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}