nyquest_interface/async/
any.rs

1//! Type-erased async client interface traits.
2//!
3//! This module provides trait definitions for type-erased asynchronous HTTP client
4//! implementations, allowing different backend implementations to be used interchangeably.
5//!
6//! The traits in this module are automatically implemented for types that implement the
7//! corresponding traits from the `async::backend` module, so backend developers don't need
8//! to implement them directly.
9
10use std::any::Any;
11use std::fmt;
12use std::pin::Pin;
13
14use futures_core::future::BoxFuture;
15use futures_io::AsyncRead;
16
17use super::backend::AsyncResponse;
18use super::Request;
19use crate::client::ClientOptions;
20use crate::Result;
21
22/// Trait for type-erased async backend implementations.
23///
24/// Automatically implemented for types implementing `AsyncBackend`.
25pub trait AnyAsyncBackend: Send + Sync + 'static {
26    /// Creates a new async client with the given options.
27    fn create_async_client(
28        &self,
29        options: ClientOptions,
30    ) -> BoxFuture<Result<Box<dyn AnyAsyncClient>>>;
31}
32
33/// Trait for type-erased async HTTP clients.
34///
35/// Automatically implemented for types implementing `AsyncClient`.
36pub trait AnyAsyncClient: Any + Send + Sync + 'static {
37    /// Provides a textual description of this client.
38    fn describe(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
39    /// Creates a cloned boxed version of this client.
40    fn clone_boxed(&self) -> Box<dyn AnyAsyncClient>;
41    /// Sends an HTTP request and returns the response.
42    fn request(&self, req: Request) -> BoxFuture<Result<Pin<Box<dyn AnyAsyncResponse>>>>;
43}
44
45/// Trait for type-erased async HTTP responses.
46///
47/// Automatically implemented for types implementing `AsyncResponse`.
48pub trait AnyAsyncResponse: AsyncRead + Any + Send + Sync + 'static {
49    /// Provides a textual description of this response.
50    fn describe(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
51    /// Returns the HTTP status code of this response.
52    fn status(&self) -> u16;
53    /// Returns the content-length of the response body, if known.
54    fn content_length(&self) -> Option<u64>;
55    /// Gets all values for the specified header.
56    fn get_header(&self, header: &str) -> Result<Vec<String>>;
57    /// Reads the response body as text.
58    fn text(self: Pin<&mut Self>) -> BoxFuture<Result<String>>;
59    /// Reads the response body as bytes.
60    fn bytes(self: Pin<&mut Self>) -> BoxFuture<Result<Vec<u8>>>;
61}
62
63// These implementations allow backend types implementing the base traits
64// to be used with the type-erased trait system automatically.
65
66impl<R> AnyAsyncResponse for R
67where
68    R: AsyncResponse,
69{
70    fn status(&self) -> u16 {
71        AsyncResponse::status(self)
72    }
73
74    fn content_length(&self) -> Option<u64> {
75        AsyncResponse::content_length(self)
76    }
77
78    fn get_header(&self, header: &str) -> Result<Vec<String>> {
79        AsyncResponse::get_header(self, header)
80    }
81
82    fn text(self: Pin<&mut Self>) -> BoxFuture<Result<String>> {
83        Box::pin(AsyncResponse::text(self))
84    }
85
86    fn bytes(self: Pin<&mut Self>) -> BoxFuture<Result<Vec<u8>>> {
87        Box::pin(AsyncResponse::bytes(self))
88    }
89
90    fn describe(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        AsyncResponse::describe(self, f)
92    }
93}
94
95impl<A> AnyAsyncBackend for A
96where
97    A: super::backend::AsyncBackend,
98    A::AsyncClient: super::backend::AsyncClient,
99{
100    fn create_async_client(
101        &self,
102        options: ClientOptions,
103    ) -> BoxFuture<Result<Box<dyn AnyAsyncClient>>> {
104        Box::pin(async {
105            super::backend::AsyncBackend::create_async_client(self, options)
106                .await
107                .map(|client| Box::new(client) as Box<dyn AnyAsyncClient>)
108        }) as _
109    }
110}
111
112impl<A> AnyAsyncClient for A
113where
114    A: super::backend::AsyncClient,
115{
116    fn describe(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        super::backend::AsyncClient::describe(self, f)
118    }
119
120    fn clone_boxed(&self) -> Box<dyn AnyAsyncClient> {
121        Box::new(self.clone())
122    }
123
124    fn request(&self, req: Request) -> BoxFuture<Result<Pin<Box<dyn AnyAsyncResponse>>>> {
125        Box::pin(async {
126            self.request(req)
127                .await
128                .map(|res| Box::pin(res) as Pin<Box<dyn AnyAsyncResponse>>)
129        }) as _
130    }
131}