1use restate_sdk_shared_core::TerminalFailure;
33use std::error::Error as StdError;
34use std::fmt;
35
36#[derive(Debug)]
37pub(crate) enum HandlerErrorInner {
38 Retryable(Box<dyn StdError + Send + Sync + 'static>),
39 Terminal(TerminalErrorInner),
40}
41
42impl fmt::Display for HandlerErrorInner {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 match self {
45 HandlerErrorInner::Retryable(e) => {
46 write!(f, "Retryable error: {}", e)
47 }
48 HandlerErrorInner::Terminal(e) => fmt::Display::fmt(e, f),
49 }
50 }
51}
52
53impl StdError for HandlerErrorInner {
54 fn source(&self) -> Option<&(dyn StdError + 'static)> {
55 match self {
56 HandlerErrorInner::Retryable(e) => Some(e.as_ref()),
57 HandlerErrorInner::Terminal(e) => Some(e),
58 }
59 }
60}
61
62#[derive(Debug)]
65pub struct HandlerError(pub(crate) HandlerErrorInner);
66
67impl<E: Into<Box<dyn StdError + Send + Sync + 'static>>> From<E> for HandlerError {
68 fn from(value: E) -> Self {
69 Self(HandlerErrorInner::Retryable(value.into()))
70 }
71}
72
73impl From<TerminalError> for HandlerError {
74 fn from(value: TerminalError) -> Self {
75 Self(HandlerErrorInner::Terminal(value.0))
76 }
77}
78
79impl AsRef<dyn StdError + Send + Sync> for HandlerError {
81 fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) {
82 &self.0
83 }
84}
85
86impl AsRef<dyn StdError> for HandlerError {
87 fn as_ref(&self) -> &(dyn StdError + 'static) {
88 &self.0
89 }
90}
91
92#[derive(Debug, Clone)]
93pub(crate) struct TerminalErrorInner {
94 code: u16,
95 message: String,
96}
97
98impl fmt::Display for TerminalErrorInner {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 write!(f, "Terminal error [{}]: {}", self.code, self.message)
101 }
102}
103
104impl StdError for TerminalErrorInner {}
105
106#[derive(Debug, Clone)]
110pub struct TerminalError(pub(crate) TerminalErrorInner);
111
112impl TerminalError {
113 pub fn new(message: impl Into<String>) -> Self {
115 Self::new_with_code(500, message)
116 }
117
118 pub fn new_with_code(code: u16, message: impl Into<String>) -> Self {
120 Self(TerminalErrorInner {
121 code,
122 message: message.into(),
123 })
124 }
125
126 pub fn with_code(mut self, code: u16) -> Self {
135 self.0.code = code;
136 self
137 }
138
139 pub fn code(&self) -> u16 {
140 self.0.code
141 }
142
143 pub fn message(&self) -> &str {
144 &self.0.message
145 }
146
147 pub fn from_error<E: StdError>(e: E) -> Self {
148 Self::new(e.to_string())
149 }
150}
151
152impl fmt::Display for TerminalError {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 fmt::Display::fmt(&self.0, f)
155 }
156}
157
158impl AsRef<dyn StdError + Send + Sync> for TerminalError {
159 fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) {
160 &self.0
161 }
162}
163
164impl AsRef<dyn StdError> for TerminalError {
165 fn as_ref(&self) -> &(dyn StdError + 'static) {
166 &self.0
167 }
168}
169
170impl From<TerminalFailure> for TerminalError {
171 fn from(value: TerminalFailure) -> Self {
172 Self(TerminalErrorInner {
173 code: value.code,
174 message: value.message,
175 })
176 }
177}
178
179impl From<TerminalError> for TerminalFailure {
180 fn from(value: TerminalError) -> Self {
181 Self {
182 code: value.0.code,
183 message: value.0.message,
184 metadata: vec![],
185 }
186 }
187}
188
189pub type HandlerResult<T> = Result<T, HandlerError>;
191
192pub trait TerminalErrorExt<T, E> {
208 fn terminal(self) -> Result<T, HandlerError>;
210}
211
212impl<T, E> TerminalErrorExt<T, E> for Result<T, E>
213where
214 E: std::fmt::Display + Send + Sync + 'static,
215{
216 fn terminal(self) -> Result<T, HandlerError> {
217 self.map_err(|err| TerminalError::new(err.to_string()).into())
218 }
219}