1use std::borrow::Cow;
2
3use serde::{de, ser};
4use thiserror::Error;
5
6use crate::parser;
7
8type NomError<T> = nom::error::Error<T>;
9
10fn transform_parse_err<T, I>(
11 err: nom::Err<NomError<I>>,
12 map_input: impl FnOnce(I) -> T,
13) -> nom::Err<NomError<T>> {
14 let make_err = |e: NomError<I>| NomError {
15 input: map_input(e.input),
16 code: e.code,
17 };
18
19 match err {
20 nom::Err::Error(e) => nom::Err::Error(make_err(e)),
21 nom::Err::Failure(e) => nom::Err::Failure(make_err(e)),
22 nom::Err::Incomplete(needed) => nom::Err::Incomplete(needed),
23 }
24}
25
26#[derive(Debug, Error)]
28pub enum Error<'a> {
29 #[error("{0}")]
31 Message(Cow<'a, str>),
32 #[error("io error: {0}")]
34 Io(#[from] std::io::Error),
35 #[error("parse error: {0}")]
37 Parse(parser::Error<'a>),
38 #[error("Redis error: {0}")]
40 Redis(Cow<'a, str>),
41}
42
43impl Error<'_> {
44 pub fn into_owned(self) -> Error<'static> {
46 match self {
47 Self::Message(msg) => Error::Message(msg.into_owned().into()),
48 Self::Io(err) => Error::Io(err),
49 Self::Parse(err) => Error::Parse(transform_parse_err(err, |i| i.into_owned().into())),
50 Self::Redis(msg) => Error::Redis(msg.into_owned().into()),
51 }
52 }
53
54 pub fn is_transient(&self) -> bool {
56 matches!(self, Self::Redis(_))
57 }
58}
59
60impl ser::Error for Error<'_> {
61 fn custom<T>(msg: T) -> Self
62 where
63 T: std::fmt::Display,
64 {
65 Self::Message(msg.to_string().into())
66 }
67}
68
69impl de::Error for Error<'_> {
70 fn custom<T>(msg: T) -> Self
71 where
72 T: std::fmt::Display,
73 {
74 Self::Message(msg.to_string().into())
75 }
76}
77
78impl<'a> From<parser::Error<'a>> for Error<'a> {
79 fn from(err: parser::Error<'a>) -> Self {
80 Self::Parse(err)
81 }
82}
83
84impl<'a> From<parser::RawError<'a>> for Error<'a> {
85 fn from(err: parser::RawError<'a>) -> Self {
86 Self::Parse(transform_parse_err(err, |i| i.into()))
87 }
88}
89
90pub type Result<'a, T, E = Error<'a>> = std::result::Result<T, E>;