1use crate::transport::TransportRequest;
2use crate::{Address, CanRetry, DapiClientError, RequestSettings};
3use dapi_grpc::mock::Mockable;
4use dapi_grpc::tonic::async_trait;
5use std::fmt::Debug;
6
7#[async_trait]
8pub trait DapiRequestExecutor {
10 async fn execute<R>(
12 &self,
13 request: R,
14 settings: RequestSettings,
15 ) -> ExecutionResult<R::Response, DapiClientError>
16 where
17 R: TransportRequest + Mockable,
18 R::Response: Mockable;
19}
20
21pub trait IntoInner<T> {
23 fn into_inner(self) -> T;
28}
29
30pub trait InnerInto<T> {
32 fn inner_into(self) -> T;
34}
35
36#[derive(Debug, Clone, thiserror::Error, Eq)]
38#[error("{inner}")]
39pub struct ExecutionError<E> {
40 pub inner: E,
42 pub retries: usize,
44 pub address: Option<Address>,
46}
47
48impl<E: PartialEq> PartialEq for ExecutionError<E> {
49 fn eq(&self, other: &Self) -> bool {
50 self.inner == other.inner && self.retries == other.retries && self.address == other.address
51 }
52}
53
54impl<F, T> InnerInto<ExecutionError<T>> for ExecutionError<F>
55where
56 F: Into<T>,
57{
58 fn inner_into(self) -> ExecutionError<T> {
60 ExecutionError {
61 inner: self.inner.into(),
62 retries: self.retries,
63 address: self.address,
64 }
65 }
66}
67
68impl<E, I> IntoInner<I> for ExecutionError<E>
69where
70 E: Into<I>,
71{
72 fn into_inner(self) -> I {
74 self.inner.into()
75 }
76}
77
78impl<E: CanRetry> CanRetry for ExecutionError<E> {
79 fn can_retry(&self) -> bool {
80 self.inner.can_retry()
81 }
82
83 fn is_no_available_addresses(&self) -> bool {
84 self.inner.is_no_available_addresses()
85 }
86
87 fn rate_limit_ban_duration(&self) -> Option<std::time::Duration> {
88 self.inner.rate_limit_ban_duration()
89 }
90}
91
92#[derive(Debug, Clone, Eq, PartialEq)]
94pub struct ExecutionResponse<R> {
95 pub inner: R,
97 pub retries: usize,
99 pub address: Address,
101}
102
103#[cfg(feature = "mocks")]
104impl<R: Default> Default for ExecutionResponse<R> {
105 fn default() -> Self {
106 Self {
107 retries: Default::default(),
108 address: "http://127.0.0.1".parse().expect("create mock address"),
109 inner: Default::default(),
110 }
111 }
112}
113
114impl<R, I> IntoInner<I> for ExecutionResponse<R>
115where
116 R: Into<I>,
117{
118 fn into_inner(self) -> I {
120 self.inner.into()
121 }
122}
123
124impl<F, T> InnerInto<ExecutionResponse<T>> for ExecutionResponse<F>
125where
126 F: Into<T>,
127{
128 fn inner_into(self) -> ExecutionResponse<T> {
130 ExecutionResponse {
131 inner: self.inner.into(),
132 retries: self.retries,
133 address: self.address,
134 }
135 }
136}
137
138pub type ExecutionResult<R, E> = Result<ExecutionResponse<R>, ExecutionError<E>>;
140
141impl<R, E> From<ExecutionResponse<R>> for ExecutionResult<R, E> {
142 fn from(response: ExecutionResponse<R>) -> Self {
143 ExecutionResult::<R, E>::Ok(response)
144 }
145}
146
147impl<R, E> From<ExecutionError<E>> for ExecutionResult<R, E> {
148 fn from(e: ExecutionError<E>) -> Self {
149 ExecutionResult::<R, E>::Err(e)
150 }
151}
152
153impl<R, E> IntoInner<Result<R, E>> for ExecutionResult<R, E> {
154 fn into_inner(self) -> Result<R, E> {
155 match self {
156 Ok(response) => Ok(response.into_inner()),
157 Err(error) => Err(error.into_inner()),
158 }
159 }
160}
161
162impl<F, FE, T, TE> InnerInto<ExecutionResult<T, TE>> for ExecutionResult<F, FE>
163where
164 F: Into<T>,
165 FE: Into<TE>,
166{
167 fn inner_into(self) -> ExecutionResult<T, TE> {
168 match self {
169 Ok(response) => Ok(response.inner_into()),
170 Err(error) => Err(error.inner_into()),
171 }
172 }
173}
174
175pub trait WrapToExecutionResult<R, RE, W>: Sized {
177 fn wrap_to_execution_result(self, result: &W) -> ExecutionResult<R, RE>;
213}
214
215impl<R, RE, TR, IR, IRE> WrapToExecutionResult<R, RE, ExecutionResponse<TR>> for Result<IR, IRE>
216where
217 R: From<IR>,
218 RE: From<IRE>,
219{
220 fn wrap_to_execution_result(self, result: &ExecutionResponse<TR>) -> ExecutionResult<R, RE> {
221 match self {
222 Ok(r) => ExecutionResult::Ok(ExecutionResponse {
223 inner: r.into(),
224 retries: result.retries,
225 address: result.address.clone(),
226 }),
227 Err(e) => ExecutionResult::Err(ExecutionError {
228 inner: e.into(),
229 retries: result.retries,
230 address: Some(result.address.clone()),
231 }),
232 }
233 }
234}
235
236#[cfg(test)]
237mod tests {
238 use super::*;
239
240 fn mock_address() -> Address {
241 "http://127.0.0.1:3000".parse().expect("valid address")
242 }
243
244 fn mock_response() -> ExecutionResponse<i32> {
245 ExecutionResponse {
246 inner: 42,
247 retries: 3,
248 address: mock_address(),
249 }
250 }
251
252 fn mock_error() -> ExecutionError<String> {
253 ExecutionError {
254 inner: "test error".to_string(),
255 retries: 2,
256 address: Some(mock_address()),
257 }
258 }
259
260 #[test]
261 fn test_execution_error_partial_eq() {
262 let err1 = mock_error();
263 let err2 = mock_error();
264 assert_eq!(err1, err2);
265
266 let err3 = ExecutionError {
267 inner: "different".to_string(),
268 retries: 2,
269 address: Some(mock_address()),
270 };
271 assert_ne!(err1, err3);
272
273 let err4 = ExecutionError {
274 inner: "test error".to_string(),
275 retries: 5,
276 address: Some(mock_address()),
277 };
278 assert_ne!(err1, err4);
279 }
280
281 #[test]
282 fn test_execution_result_from_response() {
283 let response = mock_response();
284 let result: ExecutionResult<i32, String> = response.into();
285 assert!(result.is_ok());
286 assert_eq!(result.unwrap().inner, 42);
287 }
288
289 #[test]
290 fn test_execution_result_from_error() {
291 let error = mock_error();
292 let result: ExecutionResult<i32, String> = error.into();
293 assert!(result.is_err());
294 assert_eq!(result.unwrap_err().inner, "test error");
295 }
296
297 #[test]
298 fn test_execution_result_inner_into_ok() {
299 let response = mock_response();
300 let result: ExecutionResult<i32, String> = Ok(response);
301 let converted: ExecutionResult<i64, String> = result.inner_into();
302 assert!(converted.is_ok());
303 assert_eq!(converted.unwrap().inner, 42i64);
304 }
305
306 #[test]
307 fn test_execution_result_inner_into_err() {
308 let error = mock_error();
309 let result: ExecutionResult<i32, String> = Err(error);
310 let converted: ExecutionResult<i64, String> = result.inner_into();
311 assert!(converted.is_err());
312 assert_eq!(converted.unwrap_err().inner, "test error");
313 }
314
315 #[test]
316 fn test_wrap_to_execution_result_ok() {
317 let context = mock_response();
318 let inner_result: Result<i64, String> = Ok(100);
319 let wrapped: ExecutionResult<i64, String> = inner_result.wrap_to_execution_result(&context);
320
321 let response = wrapped.unwrap();
322 assert_eq!(response.inner, 100);
323 assert_eq!(response.retries, 3);
324 assert_eq!(response.address, mock_address());
325 }
326
327 #[test]
328 fn test_wrap_to_execution_result_err() {
329 let context = mock_response();
330 let inner_result: Result<i64, String> = Err("wrapped error".to_string());
331 let wrapped: ExecutionResult<i64, String> = inner_result.wrap_to_execution_result(&context);
332
333 let error = wrapped.unwrap_err();
334 assert_eq!(error.inner, "wrapped error");
335 assert_eq!(error.retries, 3);
336 assert_eq!(error.address, Some(mock_address()));
337 }
338
339 #[test]
340 fn test_execution_response_into_inner() {
341 let response = mock_response();
342 let inner: i32 = response.into_inner();
343 assert_eq!(inner, 42);
344 }
345
346 #[test]
347 fn test_execution_response_inner_into() {
348 let response = mock_response();
349 let converted: ExecutionResponse<i64> = response.inner_into();
350 assert_eq!(converted.inner, 42i64);
351 assert_eq!(converted.retries, 3);
352 }
353
354 #[test]
355 fn test_execution_error_into_inner() {
356 let error = mock_error();
357 let inner: String = error.into_inner();
358 assert_eq!(inner, "test error");
359 }
360
361 #[test]
362 fn test_execution_error_inner_into() {
363 let error = mock_error();
364 let converted: ExecutionError<String> = error.inner_into();
365 assert_eq!(converted.inner, "test error");
366 assert_eq!(converted.retries, 2);
367 }
368
369 #[test]
370 fn test_execution_result_into_inner_ok() {
371 let result: ExecutionResult<i32, String> = Ok(mock_response());
372 let inner: Result<i32, String> = result.into_inner();
373 assert_eq!(inner.unwrap(), 42);
374 }
375
376 #[test]
377 fn test_execution_result_into_inner_err() {
378 let result: ExecutionResult<i32, String> = Err(mock_error());
379 let inner: Result<i32, String> = result.into_inner();
380 assert_eq!(inner.unwrap_err(), "test error");
381 }
382
383 #[test]
384 fn test_execution_error_can_retry_delegates() {
385 use crate::DapiClientError;
388
389 let inner = DapiClientError::NoAvailableAddresses;
390 let error = ExecutionError {
391 inner,
392 retries: 0,
393 address: None,
394 };
395
396 assert!(!error.can_retry());
397 assert!(error.is_no_available_addresses());
398 }
399
400 #[cfg(feature = "mocks")]
401 #[test]
402 fn test_execution_response_default() {
403 let response: ExecutionResponse<i32> = ExecutionResponse::default();
404 assert_eq!(response.inner, 0);
405 assert_eq!(response.retries, 0);
406 }
407}