redis/errors/
server_error.rs1use arcstr::ArcStr;
2use std::fmt;
3
4use crate::RetryMethod;
5
6#[derive(PartialEq, Debug, Clone, Copy, Eq)]
8#[non_exhaustive]
9pub enum ServerErrorKind {
10 ResponseError,
12 ExecAbort,
14 BusyLoading,
16 NoScript,
18 Moved,
20 Ask,
22 TryAgain,
24 ClusterDown,
26 CrossSlot,
28 MasterDown,
30 ReadOnly,
32 NotBusy,
34 NoSub,
36 NoPerm,
38}
39
40impl ServerErrorKind {
41 pub(crate) fn code(&self) -> &'static str {
42 match self {
43 Self::ResponseError => "ERR",
44 Self::ExecAbort => "EXECABORT",
45 Self::BusyLoading => "LOADING",
46 Self::NoScript => "NOSCRIPT",
47 Self::Moved => "MOVED",
48 Self::Ask => "ASK",
49 Self::TryAgain => "TRYAGAIN",
50 Self::ClusterDown => "CLUSTERDOWN",
51 Self::CrossSlot => "CROSSSLOT",
52 Self::MasterDown => "MASTERDOWN",
53 Self::ReadOnly => "READONLY",
54 Self::NotBusy => "NOTBUSY",
55 Self::NoSub => "NOSUB",
56 Self::NoPerm => "NOPERM",
57 }
58 }
59
60 pub(crate) fn retry_method(&self) -> RetryMethod {
61 match self {
62 Self::Moved => RetryMethod::MovedRedirect,
63 Self::Ask => RetryMethod::AskRedirect,
64
65 Self::TryAgain => RetryMethod::WaitAndRetry,
66 Self::MasterDown => RetryMethod::WaitAndRetry,
67 Self::ClusterDown => RetryMethod::WaitAndRetry,
68 Self::BusyLoading => RetryMethod::WaitAndRetry,
69
70 Self::ResponseError => RetryMethod::NoRetry,
71 Self::ReadOnly => RetryMethod::NoRetry,
72 Self::ExecAbort => RetryMethod::NoRetry,
73 Self::NoScript => RetryMethod::NoRetry,
74 Self::CrossSlot => RetryMethod::NoRetry,
75 Self::NotBusy => RetryMethod::NoRetry,
76 Self::NoSub => RetryMethod::NoRetry,
77 Self::NoPerm => RetryMethod::NoRetry,
78 }
79 }
80}
81
82#[derive(PartialEq, Debug, Clone)]
84pub struct ServerError(pub(crate) Repr);
85
86#[derive(PartialEq, Debug, Clone)]
87pub(crate) enum Repr {
88 Extension {
89 code: ArcStr,
90 detail: Option<ArcStr>,
91 },
92 Known {
93 kind: ServerErrorKind,
94 detail: Option<ArcStr>,
95 },
96}
97
98impl ServerError {
99 pub fn kind(&self) -> Option<ServerErrorKind> {
101 match &self.0 {
102 Repr::Extension { .. } => None,
103 Repr::Known { kind, .. } => Some(*kind),
104 }
105 }
106
107 pub fn code(&self) -> &str {
109 match &self.0 {
110 Repr::Extension { code, .. } => code,
111 Repr::Known { kind, .. } => kind.code(),
112 }
113 }
114
115 pub fn details(&self) -> Option<&str> {
117 match &self.0 {
118 Repr::Extension { detail, .. } => detail.as_ref().map(|str| str.as_str()),
119 Repr::Known { detail, .. } => detail.as_ref().map(|str| str.as_str()),
120 }
121 }
122
123 #[cfg(feature = "cluster-async")]
124 pub(crate) fn requires_action(&self) -> bool {
125 !matches!(
126 self.kind()
127 .map(|kind| kind.retry_method())
128 .unwrap_or(RetryMethod::NoRetry),
129 RetryMethod::NoRetry
130 )
131 }
132}
133
134impl fmt::Display for ServerError {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 match &self.0 {
137 Repr::Extension { code, detail } => {
138 fmt::Debug::fmt(&code, f)?;
139 if let Some(detail) = detail {
140 f.write_str(": ")?;
141 detail.fmt(f)?;
142 }
143 Ok(())
144 }
145 Repr::Known { kind, detail } => {
146 fmt::Debug::fmt(&kind, f)?;
147 if let Some(detail) = detail {
148 f.write_str(": ")?;
149 detail.fmt(f)?;
150 }
151 Ok(())
152 }
153 }
154 }
155}
156
157impl std::error::Error for ServerError {}