zookeeper_client/
error.rs

1use std::borrow::Cow;
2use std::fmt::{self, Display, Formatter};
3use std::sync::Arc;
4
5use static_assertions::assert_impl_all;
6use thiserror::Error;
7
8/// Errors for ZooKeeper operations.
9#[non_exhaustive]
10#[derive(Error, Clone, Debug, PartialEq, Eq)]
11pub enum Error {
12    #[error("unable to unmarshal {entity} due to {reason}")]
13    UnmarshalError { entity: &'static str, reason: &'static &'static str },
14
15    #[error("no available hosts")]
16    NoHosts,
17
18    #[error("timeout")]
19    Timeout,
20
21    #[error("unexpected error: {0}")]
22    UnexpectedError(String),
23
24    #[error("bad arguments: {0}")]
25    BadArguments(&'static &'static str),
26
27    #[error("node not exists")]
28    NoNode,
29
30    #[error("not authorized")]
31    NoAuth,
32
33    #[error("mismatch version")]
34    BadVersion,
35
36    #[error("ephemeral node can not have children")]
37    NoChildrenForEphemerals,
38
39    #[error("node already exists")]
40    NodeExists,
41
42    #[error("node has not empty children")]
43    NotEmpty,
44
45    #[error("session expired")]
46    SessionExpired,
47
48    #[error("invalid acls")]
49    InvalidAcl,
50
51    #[error("authentication failed")]
52    AuthFailed,
53
54    #[error("session moved")]
55    SessionMoved,
56
57    #[error("write request is sent to read only server")]
58    NotReadOnly,
59
60    #[error("no watcher")]
61    NoWatcher,
62
63    #[error("exceed path quota")]
64    QuotaExceeded,
65
66    #[error("request was throttled due to server heavy loading")]
67    Throttled,
68
69    #[error("server fail to marshal client request")]
70    MarshallingError,
71
72    #[error("unimplemented operation")]
73    Unimplemented,
74
75    #[error("connection to server has lost")]
76    ConnectionLoss,
77
78    #[error("ZooKeeper reconfiguration disabled")]
79    ReconfigDisabled,
80
81    #[error("unexpected error code: {0}")]
82    UnexpectedErrorCode(i32),
83
84    #[error("client has been closed")]
85    ClientClosed,
86
87    #[error("runtime condition mismatch")]
88    RuntimeInconsistent,
89
90    #[error(transparent)]
91    Custom(CustomError),
92}
93
94#[derive(Error, Clone, Debug)]
95pub struct CustomError {
96    message: Option<Arc<Cow<'static, str>>>,
97    source: Option<Arc<dyn std::error::Error + Send + Sync + 'static>>,
98}
99
100impl Display for CustomError {
101    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
102        match (self.message.as_ref(), self.source.as_ref()) {
103            (Some(message), None) => f.write_str(message),
104            (Some(message), Some(err)) => write!(f, "{message}: {err}"),
105            (None, Some(err)) => err.fmt(f),
106            _ => unreachable!("no error message or source"),
107        }
108    }
109}
110
111impl PartialEq for CustomError {
112    fn eq(&self, other: &Self) -> bool {
113        if !self.message.eq(&other.message) {
114            return false;
115        }
116        match (self.source.as_ref(), other.source.as_ref()) {
117            (Some(lhs), Some(rhs)) => Arc::ptr_eq(lhs, rhs),
118            (None, None) => true,
119            _ => false,
120        }
121    }
122}
123
124impl Eq for CustomError {}
125
126impl Error {
127    pub(crate) fn is_terminated(&self) -> bool {
128        matches!(self, Self::NoHosts | Self::SessionExpired | Self::AuthFailed | Self::ClientClosed)
129    }
130
131    pub(crate) fn has_no_data_change(&self) -> bool {
132        match self {
133            Self::NoNode
134            | Self::NoAuth
135            | Self::BadVersion
136            | Self::NoChildrenForEphemerals
137            | Self::NodeExists
138            | Self::NotEmpty
139            | Self::InvalidAcl
140            | Self::AuthFailed
141            | Self::SessionMoved
142            | Self::NotReadOnly
143            | Self::NoWatcher
144            | Self::QuotaExceeded
145            | Self::Throttled
146            | Self::MarshallingError
147            | Self::Unimplemented
148            | Self::ReconfigDisabled
149            | Self::UnexpectedErrorCode(_) => true,
150            // We are expired anyway, any ephemeral nodes will be deleted by ZooKeeper soon.
151            Self::SessionExpired => true,
152            // We are closed anyway, the session will expire soon.
153            Self::ClientClosed => true,
154            _ => false,
155        }
156    }
157
158    pub(crate) fn with_message(message: impl Into<Cow<'static, str>>) -> Self {
159        Self::Custom(CustomError { message: Some(Arc::new(message.into())), source: None })
160    }
161
162    #[allow(dead_code)]
163    pub(crate) fn with_other(
164        message: impl Into<Cow<'static, str>>,
165        source: impl std::error::Error + Send + Sync + 'static,
166    ) -> Self {
167        Self::Custom(CustomError { message: Some(Arc::new(message.into())), source: Some(Arc::new(source)) })
168    }
169
170    pub(crate) fn other(source: impl std::error::Error + Send + Sync + 'static) -> Self {
171        Self::Custom(CustomError { message: None, source: Some(Arc::new(source)) })
172    }
173}
174
175assert_impl_all!(Error: Send, Sync);
176
177impl From<std::convert::Infallible> for Error {
178    fn from(_: std::convert::Infallible) -> Error {
179        unreachable!();
180    }
181}