Skip to content

Commit

Permalink
Return impl Future instead of Pin<Box<dyn Future>>
Browse files Browse the repository at this point in the history
Returning a boxed trait object requires specifying whether the returned
future is `Send`/`Sync`, which means we can't support both `Send` and
non-`Send` async HTTP clients. The `reqwest` client returns a `Send`
future when using versions of `hyper` >= 0.14.14 (see
hyperium/hyper#2653), except in WASM builds,
for which the future is non-`Send`.

With this change, each `request_async()` method now returns
`impl Future`, which may or may not be `Send` depending on the inputs.
This provides the flexibility to support all the necessary HTTP
clients, while providing the convenience of `Send` futures for the
built-in `reqwest` client in non-WASM builds.

BREAKING CHANGES:
 - Removed `TokenRequestFuture` and `DeviceAuthorizationRequestFuture`
   type aliases.
 - Added `Future` associated type to `AsyncHttpClient` trait and changed
   `call()` method to return `Self::Future` (which may or may not be
   `Send`/`Sync`).
 - Changed each `request_async()` method to return `impl Future` instead
   of `Pin<Box<dyn Future>>`.

Fixes #255 and #260.
  • Loading branch information
ramosbugs committed Mar 10, 2024
1 parent 4f7a22f commit 6e583bd
Show file tree
Hide file tree
Showing 8 changed files with 864 additions and 540 deletions.
1,317 changes: 823 additions & 494 deletions Cargo-1.65.lock

Large diffs are not rendered by default.

23 changes: 13 additions & 10 deletions src/devicecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
AsyncHttpClient, AuthType, Client, ClientId, ClientSecret, DeviceAuthorizationUrl, DeviceCode,
EndUserVerificationUrl, EndpointState, ErrorResponse, ErrorResponseType, HttpRequest,
HttpResponse, RequestTokenError, RevocableToken, Scope, StandardErrorResponse, SyncHttpClient,
TokenIntrospectionResponse, TokenRequestFuture, TokenResponse, TokenType, TokenUrl, UserCode,
TokenIntrospectionResponse, TokenResponse, TokenType, TokenUrl, UserCode,
};

use chrono::{DateTime, Utc};
Expand All @@ -18,7 +18,6 @@ use std::fmt::Error as FormatterError;
use std::fmt::{Debug, Display, Formatter};
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::sync::Arc;
use std::time::Duration;

Expand Down Expand Up @@ -98,10 +97,6 @@ where
}
}

/// Future returned by [`DeviceAuthorizationRequest::request_async`].
pub type DeviceAuthorizationRequestFuture<'c, C, EF, TE> =
TokenRequestFuture<'c, <C as AsyncHttpClient<'c>>::Error, TE, DeviceAuthorizationResponse<EF>>;

/// The request for a set of verification codes from the authorization server.
///
/// See <https://tools.ietf.org/html/rfc8628#section-3.1>.
Expand Down Expand Up @@ -193,7 +188,12 @@ where
pub fn request_async<'c, C, EF>(
self,
http_client: &'c C,
) -> Pin<Box<DeviceAuthorizationRequestFuture<'c, C, EF, TE>>>
) -> impl Future<
Output = Result<
DeviceAuthorizationResponse<EF>,
RequestTokenError<<C as AsyncHttpClient<'c>>::Error, TE>,
>,
> + 'c
where
Self: 'c,
C: AsyncHttpClient<'c>,
Expand Down Expand Up @@ -326,9 +326,12 @@ where
http_client: &'c C,
sleep_fn: S,
timeout: Option<Duration>,
) -> Pin<
Box<TokenRequestFuture<'c, <C as AsyncHttpClient<'c>>::Error, DeviceCodeErrorResponse, TR>>,
>
) -> impl Future<
Output = Result<
TR,
RequestTokenError<<C as AsyncHttpClient<'c>>::Error, DeviceCodeErrorResponse>,
>,
> + 'c
where
Self: 'c,
C: AsyncHttpClient<'c>,
Expand Down
17 changes: 7 additions & 10 deletions src/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use url::{form_urlencoded, Url};
use std::borrow::Cow;
use std::error::Error;
use std::future::Future;
use std::pin::Pin;

/// An HTTP request.
pub type HttpRequest = http::Request<Vec<u8>>;
Expand All @@ -24,11 +23,11 @@ pub trait AsyncHttpClient<'c> {
/// Error type returned by HTTP client.
type Error: Error + 'static;

/// Future type returned by HTTP client.
type Future: Future<Output = Result<HttpResponse, Self::Error>> + 'c;

/// Perform a single HTTP request.
fn call(
&'c self,
request: HttpRequest,
) -> Pin<Box<dyn Future<Output = Result<HttpResponse, Self::Error>> + 'c>>;
fn call(&'c self, request: HttpRequest) -> Self::Future;
}
impl<'c, E, F, T> AsyncHttpClient<'c> for T
where
Expand All @@ -39,12 +38,10 @@ where
T: Fn(HttpRequest) -> F,
{
type Error = E;
type Future = F;

fn call(
&'c self,
request: HttpRequest,
) -> Pin<Box<dyn Future<Output = Result<HttpResponse, Self::Error>> + 'c>> {
Box::pin(self(request))
fn call(&'c self, request: HttpRequest) -> Self::Future {
self(request)
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/introspection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::endpoint::{endpoint_request, endpoint_response};
use crate::{
AccessToken, AsyncHttpClient, AuthType, Client, ClientId, ClientSecret, EndpointState,
ErrorResponse, ExtraTokenFields, HttpRequest, IntrospectionUrl, RequestTokenError,
RevocableToken, Scope, SyncHttpClient, TokenRequestFuture, TokenResponse, TokenType,
RevocableToken, Scope, SyncHttpClient, TokenResponse, TokenType,
};

use chrono::serde::ts_seconds_option;
Expand All @@ -13,8 +13,8 @@ use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::error::Error;
use std::fmt::Debug;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;

impl<
TE,
Expand Down Expand Up @@ -180,7 +180,7 @@ where
pub fn request_async<'c, C>(
self,
http_client: &'c C,
) -> Pin<Box<TokenRequestFuture<'c, <C as AsyncHttpClient<'c>>::Error, TE, TIR>>>
) -> impl Future<Output = Result<TIR, RequestTokenError<<C as AsyncHttpClient<'c>>::Error, TE>>> + 'c
where
Self: 'c,
C: AsyncHttpClient<'c>,
Expand Down
10 changes: 4 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,10 +524,9 @@ pub use crate::code::AuthorizationRequest;
#[cfg(all(feature = "curl", not(target_arch = "wasm32")))]
pub use crate::curl_client::CurlHttpClient;
pub use crate::devicecode::{
DeviceAccessTokenRequest, DeviceAuthorizationRequest, DeviceAuthorizationRequestFuture,
DeviceAuthorizationResponse, DeviceCodeErrorResponse, DeviceCodeErrorResponseType,
EmptyExtraDeviceAuthorizationFields, ExtraDeviceAuthorizationFields,
StandardDeviceAuthorizationResponse,
DeviceAccessTokenRequest, DeviceAuthorizationRequest, DeviceAuthorizationResponse,
DeviceCodeErrorResponse, DeviceCodeErrorResponseType, EmptyExtraDeviceAuthorizationFields,
ExtraDeviceAuthorizationFields, StandardDeviceAuthorizationResponse,
};
pub use crate::endpoint::{AsyncHttpClient, HttpRequest, HttpResponse, SyncHttpClient};
pub use crate::error::{
Expand All @@ -541,8 +540,7 @@ pub use crate::revocation::{
};
pub use crate::token::{
ClientCredentialsTokenRequest, CodeTokenRequest, EmptyExtraTokenFields, ExtraTokenFields,
PasswordTokenRequest, RefreshTokenRequest, StandardTokenResponse, TokenRequestFuture,
TokenResponse, TokenType,
PasswordTokenRequest, RefreshTokenRequest, StandardTokenResponse, TokenResponse, TokenType,
};
pub use crate::types::{
AccessToken, AuthUrl, AuthorizationCode, ClientId, ClientSecret, CsrfToken,
Expand Down
11 changes: 7 additions & 4 deletions src/reqwest_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ use std::pin::Pin;
impl<'c> AsyncHttpClient<'c> for reqwest::Client {
type Error = HttpClientError<reqwest::Error>;

fn call(
&'c self,
request: HttpRequest,
) -> Pin<Box<dyn Future<Output = Result<HttpResponse, Self::Error>> + 'c>> {
#[cfg(target_arch = "wasm32")]
type Future = Pin<Box<dyn Future<Output = Result<HttpResponse, Self::Error>> + 'c>>;
#[cfg(not(target_arch = "wasm32"))]
type Future =
Pin<Box<dyn Future<Output = Result<HttpResponse, Self::Error>> + Send + Sync + 'c>>;

fn call(&'c self, request: HttpRequest) -> Self::Future {
Box::pin(async move {
let response = self
.execute(request.try_into().map_err(Box::new)?)
Expand Down
7 changes: 3 additions & 4 deletions src/revocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ use crate::endpoint::{endpoint_request, endpoint_response, endpoint_response_sta
use crate::{
AccessToken, AsyncHttpClient, AuthType, Client, ClientId, ClientSecret, ConfigurationError,
EndpointState, ErrorResponse, ErrorResponseType, HttpRequest, RefreshToken, RequestTokenError,
RevocationUrl, SyncHttpClient, TokenIntrospectionResponse, TokenRequestFuture, TokenResponse,
TokenType,
RevocationUrl, SyncHttpClient, TokenIntrospectionResponse, TokenResponse, TokenType,
};

use serde::{Deserialize, Serialize};
Expand All @@ -13,8 +12,8 @@ use std::borrow::Cow;
use std::error::Error;
use std::fmt::Error as FormatterError;
use std::fmt::{Debug, Display, Formatter};
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;

impl<
TE,
Expand Down Expand Up @@ -302,7 +301,7 @@ where
pub fn request_async<'c, C>(
self,
http_client: &'c C,
) -> Pin<Box<TokenRequestFuture<'c, <C as AsyncHttpClient<'c>>::Error, TE, ()>>>
) -> impl Future<Output = Result<(), RequestTokenError<<C as AsyncHttpClient<'c>>::Error, TE>>> + 'c
where
Self: 'c,
C: AsyncHttpClient<'c>,
Expand Down
13 changes: 4 additions & 9 deletions src/token/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use std::error::Error;
use std::fmt::Debug;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::time::Duration;

#[cfg(test)]
Expand Down Expand Up @@ -129,10 +128,6 @@ where
}
}

/// Future returned by `request_async` methods.
pub type TokenRequestFuture<'c, RE, TE, TR> =
dyn Future<Output = Result<TR, RequestTokenError<RE, TE>>> + 'c;

/// A request to exchange an authorization code for an access token.
///
/// See <https://tools.ietf.org/html/rfc6749#section-4.1.3>.
Expand Down Expand Up @@ -237,7 +232,7 @@ where
pub fn request_async<'c, C>(
self,
http_client: &'c C,
) -> Pin<Box<TokenRequestFuture<'c, <C as AsyncHttpClient<'c>>::Error, TE, TR>>>
) -> impl Future<Output = Result<TR, RequestTokenError<<C as AsyncHttpClient<'c>>::Error, TE>>> + 'c
where
Self: 'c,
C: AsyncHttpClient<'c>,
Expand Down Expand Up @@ -322,7 +317,7 @@ where
pub fn request_async<'c, C>(
self,
http_client: &'c C,
) -> Pin<Box<TokenRequestFuture<'c, <C as AsyncHttpClient<'c>>::Error, TE, TR>>>
) -> impl Future<Output = Result<TR, RequestTokenError<<C as AsyncHttpClient<'c>>::Error, TE>>> + 'c
where
Self: 'c,
C: AsyncHttpClient<'c>,
Expand Down Expand Up @@ -429,7 +424,7 @@ where
pub fn request_async<'c, C>(
self,
http_client: &'c C,
) -> Pin<Box<TokenRequestFuture<'c, <C as AsyncHttpClient<'c>>::Error, TE, TR>>>
) -> impl Future<Output = Result<TR, RequestTokenError<<C as AsyncHttpClient<'c>>::Error, TE>>> + 'c
where
Self: 'c,
C: AsyncHttpClient<'c>,
Expand Down Expand Up @@ -535,7 +530,7 @@ where
pub fn request_async<'c, C>(
self,
http_client: &'c C,
) -> Pin<Box<TokenRequestFuture<'c, <C as AsyncHttpClient<'c>>::Error, TE, TR>>>
) -> impl Future<Output = Result<TR, RequestTokenError<<C as AsyncHttpClient<'c>>::Error, TE>>> + 'c
where
Self: 'c,
C: AsyncHttpClient<'c>,
Expand Down

0 comments on commit 6e583bd

Please sign in to comment.