1use crate::resp2::types::Frame as Resp2Frame;
2use crate::resp3::types::Frame as Resp3Frame;
3use bytes_utils::string::Utf8Error as BytesUtf8Error;
4use cookie_factory::GenError;
5use nom::error::{ErrorKind, FromExternalError, ParseError};
6use nom::{Err as NomError, Needed};
7use alloc::borrow::Cow;
8use alloc::format;
9use alloc::string::String;
10use core::borrow::Borrow;
11use core::fmt;
12use core::fmt::Debug;
13use core::str::Utf8Error;
14
15#[cfg(feature = "std")]
16use std::io::Error as IoError;
17
18pub const CRLF: &'static str = "\r\n";
20
21#[derive(Debug)]
23pub enum RedisProtocolErrorKind {
24 EncodeError,
26 BufferTooSmall(usize),
28 DecodeError,
30 #[cfg(feature = "std")]
31 IO(IoError),
33 Unknown,
35}
36
37impl PartialEq for RedisProtocolErrorKind {
38 fn eq(&self, other: &Self) -> bool {
39 use self::RedisProtocolErrorKind::*;
40
41 match *self {
42 EncodeError => match *other {
43 EncodeError => true,
44 _ => false,
45 },
46 DecodeError => match *other {
47 DecodeError => true,
48 _ => false,
49 },
50 BufferTooSmall(amt) => match *other {
51 BufferTooSmall(_amt) => amt == amt,
52 _ => false,
53 },
54 #[cfg(feature = "std")]
55 IO(_) => match *other {
56 IO(_) => true,
57 _ => false,
58 },
59 Unknown => match *other {
60 Unknown => true,
61 _ => false,
62 },
63 }
64 }
65}
66
67impl Eq for RedisProtocolErrorKind {}
68
69impl RedisProtocolErrorKind {
70 pub fn to_str(&self) -> &'static str {
71 use self::RedisProtocolErrorKind::*;
72
73 match *self {
74 EncodeError => "Encode Error",
75 DecodeError => "Decode Error",
76 Unknown => "Unknown Error",
77 #[cfg(feature = "std")]
78 IO(_) => "IO Error",
79 BufferTooSmall(_) => "Buffer too small",
80 }
81 }
82}
83
84#[derive(Debug, Eq, PartialEq)]
86pub struct RedisProtocolError {
87 desc: Cow<'static, str>,
88 kind: RedisProtocolErrorKind,
89}
90
91impl RedisProtocolError {
92 pub fn buffer_too_small(amt: usize) -> Self {
93 RedisProtocolError::new(RedisProtocolErrorKind::BufferTooSmall(amt), "")
94 }
95
96 pub fn new<S: Into<Cow<'static, str>>>(kind: RedisProtocolErrorKind, desc: S) -> Self {
97 RedisProtocolError {
98 kind,
99 desc: desc.into(),
100 }
101 }
102
103 pub fn description(&self) -> &str {
104 self.desc.borrow()
105 }
106
107 pub fn new_empty() -> Self {
108 RedisProtocolError {
109 kind: RedisProtocolErrorKind::Unknown,
110 desc: "".into(),
111 }
112 }
113
114 pub fn to_string(&self) -> String {
115 format!("{}: {}", self.kind.to_str(), self.desc)
116 }
117
118 pub fn kind(&self) -> &RedisProtocolErrorKind {
119 &self.kind
120 }
121}
122
123impl fmt::Display for RedisProtocolError {
124 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
125 write!(f, "{}: {}", self.kind.to_str(), self.desc)
126 }
127}
128
129impl From<GenError> for RedisProtocolError {
130 fn from(e: GenError) -> Self {
131 match e {
132 GenError::CustomError(i) => match i {
133 1 => RedisProtocolError::new(RedisProtocolErrorKind::EncodeError, "Invalid frame kind."),
134 2 => RedisProtocolError::new(RedisProtocolErrorKind::EncodeError, "Cannot encode NaN."),
135 3 => RedisProtocolError::new(RedisProtocolErrorKind::EncodeError, "Cannot stream non aggregate type."),
136 _ => RedisProtocolError::new_empty(),
137 },
138 GenError::InvalidOffset => RedisProtocolError::new(RedisProtocolErrorKind::EncodeError, "Invalid offset."),
139 GenError::BufferTooSmall(b) => RedisProtocolError::buffer_too_small(b),
140 _ => RedisProtocolError::new_empty(),
141 }
142 }
143}
144
145impl From<NomError<nom::error::Error<&[u8]>>> for RedisProtocolError {
146 fn from(e: NomError<nom::error::Error<&[u8]>>) -> Self {
147 if let NomError::Incomplete(Needed::Size(ref s)) = e {
148 RedisProtocolError {
149 kind: RedisProtocolErrorKind::BufferTooSmall(s.get()),
150 desc: Cow::Borrowed(""),
151 }
152 } else {
153 let desc = match e {
154 NomError::Failure(inner) => format!("Failure: {:?}", inner.code),
155 NomError::Error(inner) => format!("Error: {:?}", inner.code),
156 _ => format!("{:?}", e),
157 };
158
159 RedisProtocolError {
160 kind: RedisProtocolErrorKind::DecodeError,
161 desc: Cow::Owned(desc),
162 }
163 }
164 }
165}
166
167impl From<NomError<&[u8]>> for RedisProtocolError {
168 fn from(e: NomError<&[u8]>) -> Self {
169 if let NomError::Incomplete(Needed::Size(ref s)) = e {
170 RedisProtocolError {
171 kind: RedisProtocolErrorKind::BufferTooSmall(s.get()),
172 desc: Cow::Borrowed(""),
173 }
174 } else {
175 RedisProtocolError {
176 kind: RedisProtocolErrorKind::DecodeError,
177 desc: Cow::Owned(format!("{:?}", e)),
178 }
179 }
180 }
181}
182
183#[cfg(feature = "std")]
184impl From<IoError> for RedisProtocolError {
185 fn from(e: IoError) -> Self {
186 RedisProtocolError::new(RedisProtocolErrorKind::IO(e), "IO Error")
187 }
188}
189
190impl<I> From<RedisParseError<I>> for RedisProtocolError
191where
192 I: Debug,
193{
194 fn from(e: RedisParseError<I>) -> Self {
195 RedisProtocolError::new(RedisProtocolErrorKind::DecodeError, format!("{:?}", e))
196 }
197}
198
199impl<B> From<BytesUtf8Error<B>> for RedisProtocolError {
200 fn from(e: BytesUtf8Error<B>) -> Self {
201 e.utf8_error().into()
202 }
203}
204
205impl From<Utf8Error> for RedisProtocolError {
206 fn from(e: Utf8Error) -> Self {
207 RedisProtocolError::new(RedisProtocolErrorKind::DecodeError, format!("{}", e))
208 }
209}
210
211pub enum RedisParseError<I> {
213 Custom {
214 context: &'static str,
215 message: Cow<'static, str>,
216 },
217 Incomplete(Needed),
218 Nom(I, ErrorKind),
219}
220
221impl<I> fmt::Debug for RedisParseError<I>
222where
223 I: Debug,
224{
225 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
226 match self {
227 RedisParseError::Custom {
228 ref context,
229 ref message,
230 } => write!(f, "{}: {}", context, message),
231 RedisParseError::Nom(input, kind) => write!(f, "{:?} at {:?}", kind, input),
232 RedisParseError::Incomplete(ref needed) => write!(f, "Incomplete({:?})", needed),
233 }
234 }
235}
236
237impl<I> RedisParseError<I> {
238 pub fn new_custom<S: Into<Cow<'static, str>>>(ctx: &'static str, message: S) -> Self {
239 RedisParseError::Custom {
240 context: ctx,
241 message: message.into(),
242 }
243 }
244
245 pub fn into_nom_error(self) -> nom::Err<RedisParseError<I>> {
246 match self {
247 RedisParseError::Incomplete(n) => nom::Err::Incomplete(n),
248 _ => nom::Err::Failure(self),
249 }
250 }
251}
252
253impl<I> ParseError<I> for RedisParseError<I> {
254 fn from_error_kind(input: I, kind: ErrorKind) -> Self {
255 RedisParseError::Nom(input, kind)
256 }
257
258 fn append(_: I, _: ErrorKind, other: Self) -> Self {
259 other
260 }
261}
262
263impl<I, O> ParseError<(I, O)> for RedisParseError<I> {
264 fn from_error_kind(input: (I, O), kind: ErrorKind) -> Self {
265 RedisParseError::Nom(input.0, kind)
266 }
267
268 fn append(_: (I, O), _: ErrorKind, other: Self) -> Self {
269 other
270 }
271}
272
273impl<I, E> FromExternalError<I, E> for RedisParseError<I> {
274 fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
275 RedisParseError::Nom(input, kind)
276 }
277}
278
279impl<I, O, E> FromExternalError<(I, O), E> for RedisParseError<I> {
280 fn from_external_error(input: (I, O), kind: ErrorKind, _e: E) -> Self {
281 RedisParseError::Nom(input.0, kind)
282 }
283}
284
285impl<I> From<nom::Err<RedisParseError<I>>> for RedisParseError<I> {
286 fn from(e: NomError<RedisParseError<I>>) -> Self {
287 match e {
288 NomError::Incomplete(n) => RedisParseError::Incomplete(n),
289 NomError::Failure(e) | NomError::Error(e) => e,
290 }
291 }
292}
293
294impl<B, I> From<BytesUtf8Error<B>> for RedisParseError<I> {
295 fn from(e: BytesUtf8Error<B>) -> Self {
296 e.utf8_error().into()
297 }
298}
299
300impl<I> From<Utf8Error> for RedisParseError<I> {
301 fn from(e: Utf8Error) -> Self {
302 RedisParseError::new_custom("parse_utf8", format!("{}", e))
303 }
304}
305
306#[derive(Clone, Debug, Eq, PartialEq)]
310pub enum Redirection {
311 Moved { slot: u16, server: String },
312 Ask { slot: u16, server: String },
313}
314
315impl Redirection {
316 pub fn to_resp2_frame(&self) -> Resp2Frame {
317 let inner = match *self {
318 Redirection::Moved { ref slot, ref server } => format!("MOVED {} {}", slot, server),
319 Redirection::Ask { ref slot, ref server } => format!("ASK {} {}", slot, server),
320 };
321
322 Resp2Frame::Error(inner.into())
323 }
324
325 pub fn to_resp3_frame(&self) -> Resp3Frame {
326 let inner = match *self {
327 Redirection::Moved { ref slot, ref server } => format!("MOVED {} {}", slot, server),
328 Redirection::Ask { ref slot, ref server } => format!("ASK {} {}", slot, server),
329 };
330
331 Resp3Frame::SimpleError {
332 data: inner.into(),
333 attributes: None,
334 }
335 }
336}
337
338#[cfg(test)]
339mod tests {
340 use super::*;
341 use std::num::NonZeroUsize;
342
343 #[test]
344 fn should_create_empty_error() {
345 let e = RedisProtocolError::new_empty();
346
347 assert_eq!(e.description(), "");
348 assert_eq!(e.kind(), &RedisProtocolErrorKind::Unknown);
349 }
350
351 #[test]
352 fn should_create_encode_error() {
353 let e = RedisProtocolError::new(RedisProtocolErrorKind::EncodeError, "foo");
354
355 assert_eq!(e.description(), "foo");
356 assert_eq!(e.kind(), &RedisProtocolErrorKind::EncodeError);
357 }
358
359 #[test]
360 fn should_create_decode_error() {
361 let e = RedisProtocolError::new(RedisProtocolErrorKind::DecodeError, "foo");
362
363 assert_eq!(e.description(), "foo");
364 assert_eq!(e.kind(), &RedisProtocolErrorKind::DecodeError);
365 }
366
367 #[test]
368 fn should_create_buf_too_small_error() {
369 let e = RedisProtocolError::new(RedisProtocolErrorKind::BufferTooSmall(10), "foo");
370
371 assert_eq!(e.description(), "foo");
372 assert_eq!(e.kind(), &RedisProtocolErrorKind::BufferTooSmall(10));
373 }
374
375 #[test]
376 fn should_cast_from_nom_incomplete() {
377 let n: NomError<&[u8]> = NomError::Incomplete(Needed::Size(NonZeroUsize::new(10).unwrap()));
378 let e = RedisProtocolError::from(n);
379
380 assert_eq!(e.kind(), &RedisProtocolErrorKind::BufferTooSmall(10));
381 }
382
383 #[test]
384 fn should_print_error_kinds() {
385 assert_eq!(RedisProtocolErrorKind::EncodeError.to_str(), "Encode Error");
386 assert_eq!(RedisProtocolErrorKind::DecodeError.to_str(), "Decode Error");
387 assert_eq!(RedisProtocolErrorKind::Unknown.to_str(), "Unknown Error");
388 assert_eq!(RedisProtocolErrorKind::BufferTooSmall(10).to_str(), "Buffer too small");
389 }
390}