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
88#[derive(Debug, Clone, Eq, PartialEq)]
90pub struct ExecutionResponse<R> {
91 pub inner: R,
93 pub retries: usize,
95 pub address: Address,
97}
98
99#[cfg(feature = "mocks")]
100impl<R: Default> Default for ExecutionResponse<R> {
101 fn default() -> Self {
102 Self {
103 retries: Default::default(),
104 address: "http://127.0.0.1".parse().expect("create mock address"),
105 inner: Default::default(),
106 }
107 }
108}
109
110impl<R, I> IntoInner<I> for ExecutionResponse<R>
111where
112 R: Into<I>,
113{
114 fn into_inner(self) -> I {
116 self.inner.into()
117 }
118}
119
120impl<F, T> InnerInto<ExecutionResponse<T>> for ExecutionResponse<F>
121where
122 F: Into<T>,
123{
124 fn inner_into(self) -> ExecutionResponse<T> {
126 ExecutionResponse {
127 inner: self.inner.into(),
128 retries: self.retries,
129 address: self.address,
130 }
131 }
132}
133
134pub type ExecutionResult<R, E> = Result<ExecutionResponse<R>, ExecutionError<E>>;
136
137impl<R, E> From<ExecutionResponse<R>> for ExecutionResult<R, E> {
138 fn from(response: ExecutionResponse<R>) -> Self {
139 ExecutionResult::<R, E>::Ok(response)
140 }
141}
142
143impl<R, E> From<ExecutionError<E>> for ExecutionResult<R, E> {
144 fn from(e: ExecutionError<E>) -> Self {
145 ExecutionResult::<R, E>::Err(e)
146 }
147}
148
149impl<R, E> IntoInner<Result<R, E>> for ExecutionResult<R, E> {
150 fn into_inner(self) -> Result<R, E> {
151 match self {
152 Ok(response) => Ok(response.into_inner()),
153 Err(error) => Err(error.into_inner()),
154 }
155 }
156}
157
158impl<F, FE, T, TE> InnerInto<ExecutionResult<T, TE>> for ExecutionResult<F, FE>
159where
160 F: Into<T>,
161 FE: Into<TE>,
162{
163 fn inner_into(self) -> ExecutionResult<T, TE> {
164 match self {
165 Ok(response) => Ok(response.inner_into()),
166 Err(error) => Err(error.inner_into()),
167 }
168 }
169}
170
171pub trait WrapToExecutionResult<R, RE, W>: Sized {
173 fn wrap_to_execution_result(self, result: &W) -> ExecutionResult<R, RE>;
209}
210
211impl<R, RE, TR, IR, IRE> WrapToExecutionResult<R, RE, ExecutionResponse<TR>> for Result<IR, IRE>
212where
213 R: From<IR>,
214 RE: From<IRE>,
215{
216 fn wrap_to_execution_result(self, result: &ExecutionResponse<TR>) -> ExecutionResult<R, RE> {
217 match self {
218 Ok(r) => ExecutionResult::Ok(ExecutionResponse {
219 inner: r.into(),
220 retries: result.retries,
221 address: result.address.clone(),
222 }),
223 Err(e) => ExecutionResult::Err(ExecutionError {
224 inner: e.into(),
225 retries: result.retries,
226 address: Some(result.address.clone()),
227 }),
228 }
229 }
230}
231
232#[cfg(test)]
233mod tests {
234 use super::*;
235
236 fn mock_address() -> Address {
237 "http://127.0.0.1:3000".parse().expect("valid address")
238 }
239
240 fn mock_response() -> ExecutionResponse<i32> {
241 ExecutionResponse {
242 inner: 42,
243 retries: 3,
244 address: mock_address(),
245 }
246 }
247
248 fn mock_error() -> ExecutionError<String> {
249 ExecutionError {
250 inner: "test error".to_string(),
251 retries: 2,
252 address: Some(mock_address()),
253 }
254 }
255
256 #[test]
257 fn test_execution_error_partial_eq() {
258 let err1 = mock_error();
259 let err2 = mock_error();
260 assert_eq!(err1, err2);
261
262 let err3 = ExecutionError {
263 inner: "different".to_string(),
264 retries: 2,
265 address: Some(mock_address()),
266 };
267 assert_ne!(err1, err3);
268
269 let err4 = ExecutionError {
270 inner: "test error".to_string(),
271 retries: 5,
272 address: Some(mock_address()),
273 };
274 assert_ne!(err1, err4);
275 }
276
277 #[test]
278 fn test_execution_result_from_response() {
279 let response = mock_response();
280 let result: ExecutionResult<i32, String> = response.into();
281 assert!(result.is_ok());
282 assert_eq!(result.unwrap().inner, 42);
283 }
284
285 #[test]
286 fn test_execution_result_from_error() {
287 let error = mock_error();
288 let result: ExecutionResult<i32, String> = error.into();
289 assert!(result.is_err());
290 assert_eq!(result.unwrap_err().inner, "test error");
291 }
292
293 #[test]
294 fn test_execution_result_inner_into_ok() {
295 let response = mock_response();
296 let result: ExecutionResult<i32, String> = Ok(response);
297 let converted: ExecutionResult<i64, String> = result.inner_into();
298 assert!(converted.is_ok());
299 assert_eq!(converted.unwrap().inner, 42i64);
300 }
301
302 #[test]
303 fn test_execution_result_inner_into_err() {
304 let error = mock_error();
305 let result: ExecutionResult<i32, String> = Err(error);
306 let converted: ExecutionResult<i64, String> = result.inner_into();
307 assert!(converted.is_err());
308 assert_eq!(converted.unwrap_err().inner, "test error");
309 }
310
311 #[test]
312 fn test_wrap_to_execution_result_ok() {
313 let context = mock_response();
314 let inner_result: Result<i64, String> = Ok(100);
315 let wrapped: ExecutionResult<i64, String> = inner_result.wrap_to_execution_result(&context);
316
317 let response = wrapped.unwrap();
318 assert_eq!(response.inner, 100);
319 assert_eq!(response.retries, 3);
320 assert_eq!(response.address, mock_address());
321 }
322
323 #[test]
324 fn test_wrap_to_execution_result_err() {
325 let context = mock_response();
326 let inner_result: Result<i64, String> = Err("wrapped error".to_string());
327 let wrapped: ExecutionResult<i64, String> = inner_result.wrap_to_execution_result(&context);
328
329 let error = wrapped.unwrap_err();
330 assert_eq!(error.inner, "wrapped error");
331 assert_eq!(error.retries, 3);
332 assert_eq!(error.address, Some(mock_address()));
333 }
334
335 #[test]
336 fn test_execution_response_into_inner() {
337 let response = mock_response();
338 let inner: i32 = response.into_inner();
339 assert_eq!(inner, 42);
340 }
341
342 #[test]
343 fn test_execution_response_inner_into() {
344 let response = mock_response();
345 let converted: ExecutionResponse<i64> = response.inner_into();
346 assert_eq!(converted.inner, 42i64);
347 assert_eq!(converted.retries, 3);
348 }
349
350 #[test]
351 fn test_execution_error_into_inner() {
352 let error = mock_error();
353 let inner: String = error.into_inner();
354 assert_eq!(inner, "test error");
355 }
356
357 #[test]
358 fn test_execution_error_inner_into() {
359 let error = mock_error();
360 let converted: ExecutionError<String> = error.inner_into();
361 assert_eq!(converted.inner, "test error");
362 assert_eq!(converted.retries, 2);
363 }
364
365 #[test]
366 fn test_execution_result_into_inner_ok() {
367 let result: ExecutionResult<i32, String> = Ok(mock_response());
368 let inner: Result<i32, String> = result.into_inner();
369 assert_eq!(inner.unwrap(), 42);
370 }
371
372 #[test]
373 fn test_execution_result_into_inner_err() {
374 let result: ExecutionResult<i32, String> = Err(mock_error());
375 let inner: Result<i32, String> = result.into_inner();
376 assert_eq!(inner.unwrap_err(), "test error");
377 }
378
379 #[test]
380 fn test_execution_error_can_retry_delegates() {
381 use crate::DapiClientError;
384
385 let inner = DapiClientError::NoAvailableAddresses;
386 let error = ExecutionError {
387 inner,
388 retries: 0,
389 address: None,
390 };
391
392 assert!(!error.can_retry());
393 assert!(error.is_no_available_addresses());
394 }
395
396 #[cfg(feature = "mocks")]
397 #[test]
398 fn test_execution_response_default() {
399 let response: ExecutionResponse<i32> = ExecutionResponse::default();
400 assert_eq!(response.inner, 0);
401 assert_eq!(response.retries, 0);
402 }
403}