1use std::fmt;
2use std::ops::{Deref, DerefMut};
3
4use thiserror::Error;
5
6#[derive(Error, Debug, PartialEq)]
8pub enum RedsyncError {
9 #[error("{0}")]
10 RedisError(#[from] redis::RedisError),
11 #[error("unexpected response from Redis: {0:?}")]
12 UnexpectedResponse(redis::Value),
13
14 #[error("requested resource is current locked")]
15 ResourceLocked,
16 #[error("invalid or expired lease on lock")]
17 InvalidLease,
18
19 #[error("lock attempt failed: max retries exceeded: {0}")]
20 LockRetriesExceeded(MultiError),
21 #[error("extend attempt failed: max retries exceeded: {0}")]
22 ExtendRetriesExceeded(MultiError),
23 #[error("unlock attempt failed: {0}")]
24 UnlockFailed(MultiError),
25}
26
27#[derive(Debug, Default, PartialEq)]
29pub struct MultiError(Vec<RedsyncError>);
30
31impl MultiError {
32 pub fn new() -> Self {
33 Default::default()
34 }
35
36 pub fn includes(&self, e: RedsyncError) -> bool {
37 self.contains(&e)
38 }
39
40 pub(crate) fn reset(&mut self) {
41 self.clear()
42 }
43}
44
45impl Deref for MultiError {
46 type Target = Vec<RedsyncError>;
47
48 fn deref(&self) -> &Self::Target {
49 &self.0
50 }
51}
52
53impl DerefMut for MultiError {
54 fn deref_mut(&mut self) -> &mut Self::Target {
55 &mut self.0
56 }
57}
58
59impl fmt::Display for MultiError {
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 write!(f, "{} errors occurred:", self.len())?;
62 for error in self.iter() {
63 write!(f, "\n\t * {}", error)?;
64 }
65
66 Ok(())
67 }
68}