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    Other,
19}
20
21impl std::fmt::Display for ViturRequestErrorKind {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        write!(
24            f,
25            "{}",
26            match self {
27                Self::PrepareRequest => "PrepareRequest",
28                Self::SendRequest => "SendRequest",
29                Self::NotFound => "NotFound",
30                Self::FailureResponse => "FailureResponse",
31                Self::ParseResponse => "ParseResponse",
32                Self::Other => "Other",
33            }
34        )
35    }
36}
37
38#[derive(Debug, Error)]
39#[error("{kind}: {message}: {error}")]
40pub struct ViturRequestError {
41    pub kind: ViturRequestErrorKind,
42    pub message: &'static str,
43    pub error: ShareableError,
44    can_retry: bool,
45}
46
47// ViturRequestError should be able to be sent and shared between threads to be able to support
48// async as well as `anyhow!` for async.
49assert_impl_all!(ViturRequestError: Send, Sync);
50
51impl ViturRequestError {
52    #[inline]
53    pub fn prepare(message: &'static str, error: impl StdError + 'static + Send + Sync) -> Self {
54        Self {
55            kind: ViturRequestErrorKind::PrepareRequest,
56            message,
57            error: Box::new(error),
58            can_retry: false,
59        }
60    }
61
62    #[inline]
63    pub fn parse(message: &'static str, error: impl StdError + 'static + Send + Sync) -> Self {
64        Self {
65            kind: ViturRequestErrorKind::ParseResponse,
66            message,
67            error: Box::new(error),
68            can_retry: false,
69        }
70    }
71
72    #[inline]
73    pub fn send(message: &'static str, error: impl StdError + 'static + Send + Sync) -> Self {
74        Self {
75            kind: ViturRequestErrorKind::SendRequest,
76            message,
77            error: Box::new(error),
78            can_retry: false,
79        }
80    }
81
82    #[inline]
83    pub fn not_found(message: &'static str, error: impl StdError + 'static + Send + Sync) -> Self {
84        Self {
85            kind: ViturRequestErrorKind::NotFound,
86            message,
87            error: Box::new(error),
88            can_retry: false,
89        }
90    }
91
92    #[inline]
93    pub fn response(message: &'static str, error: impl StdError + 'static + Send + Sync) -> Self {
94        Self {
95            kind: ViturRequestErrorKind::FailureResponse,
96            message,
97            error: Box::new(error),
98            can_retry: false,
99        }
100    }
101
102    #[inline]
103    pub fn other(message: &'static str, error: impl StdError + 'static + Send + Sync) -> Self {
104        Self {
105            kind: ViturRequestErrorKind::Other,
106            message,
107            error: Box::new(error),
108            can_retry: false,
109        }
110    }
111
112    pub fn with_retryable(mut self, can_retry: bool) -> Self {
113        self.can_retry = can_retry;
114        self
115    }
116
117    pub fn retryable(self) -> Self {
118        self.with_retryable(true)
119    }
120}
121
122impl RetryableError for ViturRequestError {
123    fn can_retry(&self) -> bool {
124        self.can_retry
125    }
126}