Skip to main content

resp_async/
response.rs

1use bytes::Bytes;
2use std::convert::Infallible;
3
4use crate::resp::Value;
5
6/// RESP response type returned by handlers.
7pub type Response = Value;
8
9/// A lightweight RESP error for mapping failures to protocol responses.
10#[derive(Debug, Clone, Eq, PartialEq)]
11pub enum RespError {
12    /// Invalid client data or protocol violation.
13    InvalidData(Bytes),
14    /// Authentication required.
15    NoAuth,
16    /// Internal server error.
17    Internal,
18}
19
20impl RespError {
21    /// Build an invalid data error with an `ERR`-prefixed message.
22    pub fn invalid_data(msg: impl Into<Bytes>) -> Self {
23        let msg = msg.into();
24        if msg.starts_with(b"ERR ") {
25            RespError::InvalidData(msg)
26        } else {
27            let mut buf = Vec::with_capacity(4 + msg.len());
28            buf.extend_from_slice(b"ERR ");
29            buf.extend_from_slice(&msg);
30            RespError::InvalidData(Bytes::from(buf))
31        }
32    }
33
34    /// Build an internal error response.
35    pub fn internal() -> Self {
36        RespError::Internal
37    }
38}
39
40/// Convert a handler result into a RESP response.
41pub trait IntoResponse {
42    fn into_response(self) -> Response;
43}
44
45impl IntoResponse for Response {
46    fn into_response(self) -> Response {
47        self
48    }
49}
50
51impl IntoResponse for RespError {
52    fn into_response(self) -> Response {
53        match self {
54            RespError::InvalidData(msg) => Value::Error(msg),
55            RespError::NoAuth => {
56                Value::Error(Bytes::from_static(b"NOAUTH Authentication required."))
57            }
58            RespError::Internal => Value::Error(Bytes::from_static(b"ERR internal error")),
59        }
60    }
61}
62
63impl<T> IntoResponse for Result<T, RespError>
64where
65    T: IntoResponse,
66{
67    fn into_response(self) -> Response {
68        match self {
69            Ok(value) => value.into_response(),
70            Err(err) => err.into_response(),
71        }
72    }
73}
74
75impl IntoResponse for Bytes {
76    fn into_response(self) -> Response {
77        Value::Bulk(self)
78    }
79}
80
81impl IntoResponse for Vec<u8> {
82    fn into_response(self) -> Response {
83        Value::Bulk(Bytes::from(self))
84    }
85}
86
87impl IntoResponse for &'static [u8] {
88    fn into_response(self) -> Response {
89        Value::Bulk(Bytes::from_static(self))
90    }
91}
92
93impl IntoResponse for &'static str {
94    fn into_response(self) -> Response {
95        Value::Bulk(Bytes::from_static(self.as_bytes()))
96    }
97}
98
99impl IntoResponse for String {
100    fn into_response(self) -> Response {
101        Value::Bulk(Bytes::from(self.into_bytes()))
102    }
103}
104
105impl IntoResponse for Infallible {
106    fn into_response(self) -> Response {
107        match self {}
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn invalid_data_prefixes_err() {
117        let err = RespError::invalid_data("oops");
118        if let RespError::InvalidData(msg) = err {
119            assert!(msg.starts_with(b"ERR "));
120        } else {
121            panic!("expected InvalidData");
122        }
123    }
124
125    #[test]
126    fn result_into_response() {
127        let ok: Result<Response, RespError> = Ok(Value::Integer(1));
128        assert_eq!(ok.into_response(), Value::Integer(1));
129        let err: Result<Response, RespError> = Err(RespError::Internal);
130        assert_eq!(
131            err.into_response(),
132            Value::Error(Bytes::from_static(b"ERR internal error"))
133        );
134    }
135}