zerokms_protocol/
error.rs

1use static_assertions::assert_impl_all;
2use std::error::Error as StdError;
3use thiserror::Error;
4
5pub trait RetryableError {
6    fn can_retry(&self) -> bool;
7}
8
9type ShareableError = Box<dyn StdError + Send + Sync>;
10
11#[derive(Debug)]
12pub enum ViturRequestErrorKind {
13    PrepareRequest,
14    SendRequest,
15    NotFound,
16    FailureResponse,
17    ParseResponse,
18    Unauthorized,
19    Forbidden,
20    Other,
21}
22
23impl std::fmt::Display for ViturRequestErrorKind {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        write!(
26            f,
27            "{}",
28            match self {
29                Self::PrepareRequest => "PrepareRequest",
30                Self::SendRequest => "SendRequest",
31                Self::NotFound => "NotFound",
32                Self::FailureResponse => "FailureResponse",
33                Self::ParseResponse => "ParseResponse",
34                Self::Unauthorized => "Unauthorized",
35                Self::Forbidden => "Forbidden",
36                Self::Other => "Other",
37            }
38        )
39    }
40}
41
42#[derive(Debug, Error)]
43#[error("{kind}: {message}: {error}")]
44pub struct ViturRequestError {
45    pub kind: ViturRequestErrorKind,
46    pub message: &'static str,
47    pub error: ShareableError,
48    can_retry: bool,
49}
50
51// ViturRequestError should be able to be sent and shared between threads to be able to support
52// async as well as `anyhow!` for async.
53assert_impl_all!(ViturRequestError: Send, Sync);
54
55impl ViturRequestError {
56    #[inline]
57    pub fn new(
58        kind: ViturRequestErrorKind,
59        message: &'static str,
60        error: impl StdError + 'static + Send + Sync,
61    ) -> Self {
62        Self {
63            kind,
64            message,
65            error: Box::new(error),
66            can_retry: false,
67        }
68    }
69
70    #[inline]
71    pub fn prepare(message: &'static str, error: impl StdError + 'static + Send + Sync) -> Self {
72        Self {
73            kind: ViturRequestErrorKind::PrepareRequest,
74            message,
75            error: Box::new(error),
76            can_retry: false,
77        }
78    }
79
80    #[inline]
81    pub fn parse(message: &'static str, error: impl StdError + 'static + Send + Sync) -> Self {
82        Self {
83            kind: ViturRequestErrorKind::ParseResponse,
84            message,
85            error: Box::new(error),
86            can_retry: false,
87        }
88    }
89
90    #[inline]
91    pub fn send(message: &'static str, error: impl StdError + 'static + Send + Sync) -> Self {
92        Self {
93            kind: ViturRequestErrorKind::SendRequest,
94            message,
95            error: Box::new(error),
96            can_retry: false,
97        }
98    }
99
100    #[inline]
101    pub fn not_found(message: &'static str, error: impl StdError + 'static + Send + Sync) -> Self {
102        Self {
103            kind: ViturRequestErrorKind::NotFound,
104            message,
105            error: Box::new(error),
106            can_retry: false,
107        }
108    }
109
110    #[inline]
111    pub fn response(message: &'static str, error: impl StdError + 'static + Send + Sync) -> Self {
112        Self {
113            kind: ViturRequestErrorKind::FailureResponse,
114            message,
115            error: Box::new(error),
116            can_retry: false,
117        }
118    }
119
120    #[inline]
121    pub fn forbidden(message: &'static str, error: impl StdError + 'static + Send + Sync) -> Self {
122        Self {
123            kind: ViturRequestErrorKind::Forbidden,
124            message,
125            error: Box::new(error),
126            can_retry: false,
127        }
128    }
129
130    #[inline]
131    pub fn other(message: &'static str, error: impl StdError + 'static + Send + Sync) -> Self {
132        Self {
133            kind: ViturRequestErrorKind::Other,
134            message,
135            error: Box::new(error),
136            can_retry: false,
137        }
138    }
139
140    pub fn with_retryable(mut self, can_retry: bool) -> Self {
141        self.can_retry = can_retry;
142        self
143    }
144
145    pub fn retryable(self) -> Self {
146        self.with_retryable(true)
147    }
148}
149
150impl RetryableError for ViturRequestError {
151    fn can_retry(&self) -> bool {
152        self.can_retry
153    }
154}