Skip to content

Commit 75a742f

Browse files
authored
Merge pull request #35 from jbr/use-async-trait
Switch to using async_trait
2 parents 968a0f1 + a943eb9 commit 75a742f

File tree

6 files changed

+91
-83
lines changed

6 files changed

+91
-83
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ async-native-tls = { version = "0.3.1", optional = true }
3737
# reqwest-client
3838
hyper = { version = "0.13.6", features = ["tcp"], optional = true }
3939
hyper-tls = { version = "0.4.3", optional = true }
40+
async-trait = "0.1.37"
4041

4142
# isahc-client
4243
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]

src/h1.rs

Lines changed: 46 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
//! http-client implementation for async-h1.
22
3-
use super::{Error, HttpClient, Request, Response};
3+
use super::{async_trait, Error, HttpClient, Request, Response};
44

55
use async_h1::client;
6-
use futures::future::BoxFuture;
76
use http_types::StatusCode;
87

98
/// Async-h1 based HTTP Client.
@@ -29,56 +28,55 @@ impl Clone for H1Client {
2928
}
3029
}
3130

31+
#[async_trait]
3232
impl HttpClient for H1Client {
33-
fn send(&self, mut req: Request) -> BoxFuture<'static, Result<Response, Error>> {
34-
Box::pin(async move {
35-
// Insert host
36-
let host = req
37-
.url()
38-
.host_str()
39-
.ok_or_else(|| Error::from_str(StatusCode::BadRequest, "missing hostname"))?
40-
.to_string();
41-
42-
let scheme = req.url().scheme();
43-
if scheme != "http" && scheme != "https" {
44-
return Err(Error::from_str(
45-
StatusCode::BadRequest,
46-
format!("invalid url scheme '{}'", scheme),
47-
));
33+
async fn send(&self, mut req: Request) -> Result<Response, Error> {
34+
// Insert host
35+
let host = req
36+
.url()
37+
.host_str()
38+
.ok_or_else(|| Error::from_str(StatusCode::BadRequest, "missing hostname"))?
39+
.to_string();
40+
41+
let scheme = req.url().scheme();
42+
if scheme != "http" && scheme != "https" {
43+
return Err(Error::from_str(
44+
StatusCode::BadRequest,
45+
format!("invalid url scheme '{}'", scheme),
46+
));
47+
}
48+
49+
let addr = req
50+
.url()
51+
.socket_addrs(|| match req.url().scheme() {
52+
"http" => Some(80),
53+
"https" => Some(443),
54+
_ => None,
55+
})?
56+
.into_iter()
57+
.next()
58+
.ok_or_else(|| Error::from_str(StatusCode::BadRequest, "missing valid address"))?;
59+
60+
log::trace!("> Scheme: {}", scheme);
61+
62+
match scheme {
63+
"http" => {
64+
let stream = async_std::net::TcpStream::connect(addr).await?;
65+
req.set_peer_addr(stream.peer_addr().ok());
66+
req.set_local_addr(stream.local_addr().ok());
67+
client::connect(stream, req).await
4868
}
69+
"https" => {
70+
let raw_stream = async_std::net::TcpStream::connect(addr).await?;
71+
req.set_peer_addr(raw_stream.peer_addr().ok());
72+
req.set_local_addr(raw_stream.local_addr().ok());
4973

50-
let addr = req
51-
.url()
52-
.socket_addrs(|| match req.url().scheme() {
53-
"http" => Some(80),
54-
"https" => Some(443),
55-
_ => None,
56-
})?
57-
.into_iter()
58-
.next()
59-
.ok_or_else(|| Error::from_str(StatusCode::BadRequest, "missing valid address"))?;
60-
61-
log::trace!("> Scheme: {}", scheme);
62-
63-
match scheme {
64-
"http" => {
65-
let stream = async_std::net::TcpStream::connect(addr).await?;
66-
req.set_peer_addr(stream.peer_addr().ok());
67-
req.set_local_addr(stream.local_addr().ok());
68-
client::connect(stream, req).await
69-
}
70-
"https" => {
71-
let raw_stream = async_std::net::TcpStream::connect(addr).await?;
72-
req.set_peer_addr(raw_stream.peer_addr().ok());
73-
req.set_local_addr(raw_stream.local_addr().ok());
74-
75-
let stream = async_native_tls::connect(host, raw_stream).await?;
76-
77-
client::connect(stream, req).await
78-
}
79-
_ => unreachable!(),
74+
let stream = async_native_tls::connect(host, raw_stream).await?;
75+
76+
client::connect(stream, req).await
8077
}
81-
})
78+
_ => unreachable!(),
79+
}
8280
}
8381
}
8482

src/hyper.rs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! http-client implementation for reqwest
22
3-
use super::{Error, HttpClient, Request, Response};
3+
use super::{async_trait, Error, HttpClient, Request, Response};
44
use http_types::headers::{HeaderName, HeaderValue};
55
use http_types::StatusCode;
66
use hyper::body::HttpBody;
@@ -21,29 +21,28 @@ impl HyperClient {
2121
}
2222
}
2323

24+
#[async_trait]
2425
impl HttpClient for HyperClient {
25-
fn send(&self, req: Request) -> futures::future::BoxFuture<'static, Result<Response, Error>> {
26-
Box::pin(async move {
27-
let req = HyperHttpRequest::try_from(req).await?.into_inner();
28-
// UNWRAP: Scheme guaranteed to be "http" or "https" as part of conversion
29-
let scheme = req.uri().scheme_str().unwrap();
30-
31-
let response = match scheme {
32-
"http" => {
33-
let client = hyper::Client::builder().build_http::<hyper::Body>();
34-
client.request(req).await
35-
}
36-
"https" => {
37-
let https = HttpsConnector::new();
38-
let client = hyper::Client::builder().build::<_, hyper::Body>(https);
39-
client.request(req).await
40-
}
41-
_ => unreachable!(),
42-
}?;
43-
44-
let resp = HttpTypesResponse::try_from(response).await?.into_inner();
45-
Ok(resp)
46-
})
26+
async fn send(&self, req: Request) -> Result<Response, Error> {
27+
let req = HyperHttpRequest::try_from(req).await?.into_inner();
28+
// UNWRAP: Scheme guaranteed to be "http" or "https" as part of conversion
29+
let scheme = req.uri().scheme_str().unwrap();
30+
31+
let response = match scheme {
32+
"http" => {
33+
let client = hyper::Client::builder().build_http::<hyper::Body>();
34+
client.request(req).await
35+
}
36+
"https" => {
37+
let https = HttpsConnector::new();
38+
let client = hyper::Client::builder().build::<_, hyper::Body>(https);
39+
client.request(req).await
40+
}
41+
_ => unreachable!(),
42+
}?;
43+
44+
let resp = HttpTypesResponse::try_from(response).await?.into_inner();
45+
Ok(resp)
4746
}
4847
}
4948

src/isahc.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
//! http-client implementation for isahc
22
3-
use super::{Body, Error, HttpClient, Request, Response};
3+
use super::{async_trait, Body, Error, HttpClient, Request, Response};
44

55
use async_std::io::BufReader;
6-
use futures::future::BoxFuture;
76
use isahc::http;
87
use std::sync::Arc;
98

@@ -41,8 +40,9 @@ impl Clone for IsahcClient {
4140
}
4241
}
4342

43+
#[async_trait]
4444
impl HttpClient for IsahcClient {
45-
fn send(&self, mut req: Request) -> BoxFuture<'static, Result<Response, Error>> {
45+
async fn send(&self, mut req: Request) -> Result<Response, Error> {
4646
let client = self.client.clone();
4747
Box::pin(async move {
4848
let mut builder = http::Request::builder()

src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
forbid(unsafe_code)
1515
)]
1616

17-
use futures::future::BoxFuture;
18-
1917
#[cfg_attr(feature = "docs", doc(cfg(curl_client)))]
2018
#[cfg(all(feature = "curl_client", not(target_arch = "wasm32")))]
2119
pub mod isahc;
@@ -42,6 +40,7 @@ pub type Request = http_types::Request;
4240
/// An HTTP Response type with a streaming body.
4341
pub type Response = http_types::Response;
4442

43+
pub use async_trait::async_trait;
4544
pub use http_types;
4645

4746
/// An abstract HTTP client.
@@ -56,9 +55,10 @@ pub use http_types;
5655
/// new requests. In order to enable this efficiently an `HttpClient` instance may want to be passed
5756
/// though middleware for one of its own requests, and in order to do so should be wrapped in an
5857
/// `Rc`/`Arc` to enable reference cloning.
58+
#[async_trait]
5959
pub trait HttpClient: std::fmt::Debug + Unpin + Send + Sync + 'static {
6060
/// Perform a request.
61-
fn send(&self, req: Request) -> BoxFuture<'static, Result<Response, Error>>;
61+
async fn send(&self, req: Request) -> Result<Response, Error>;
6262
}
6363

6464
/// The raw body of an http request or response.

src/wasm.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
33
use super::{http_types::Headers, Body, Error, HttpClient, Request, Response};
44

5-
use futures::future::BoxFuture;
65
use futures::prelude::*;
76

87
use std::convert::TryFrom;
@@ -29,8 +28,15 @@ impl Clone for WasmClient {
2928
}
3029

3130
impl HttpClient for WasmClient {
32-
fn send(&self, req: Request) -> BoxFuture<'static, Result<Response, Error>> {
33-
let fut = Box::pin(async move {
31+
fn send<'a, 'async_trait>(
32+
&'a self,
33+
req: Request,
34+
) -> Pin<Box<dyn Future<Output = Result<Response, Error>> + Send + 'async_trait>>
35+
where
36+
'a: 'async_trait,
37+
Self: 'async_trait,
38+
{
39+
InnerFuture::new(async move {
3440
let req: fetch::Request = fetch::Request::new(req).await?;
3541
let mut res = req.send().await?;
3642

@@ -44,16 +50,20 @@ impl HttpClient for WasmClient {
4450
}
4551

4652
Ok(response)
47-
});
48-
49-
Box::pin(InnerFuture { fut })
53+
})
5054
}
5155
}
5256

5357
struct InnerFuture {
5458
fut: Pin<Box<dyn Future<Output = Result<Response, Error>> + 'static>>,
5559
}
5660

61+
impl InnerFuture {
62+
fn new<F: Future<Output = Result<Response, Error>> + 'static>(fut: F) -> Pin<Box<Self>> {
63+
Box::pin(Self { fut: Box::pin(fut) })
64+
}
65+
}
66+
5767
// This is safe because WASM doesn't have threads yet. Once WASM supports threads we should use a
5868
// thread to park the blocking implementation until it's been completed.
5969
unsafe impl Send for InnerFuture {}

0 commit comments

Comments
 (0)