Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use RPITIT for FromRequest #3192

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 3 additions & 4 deletions actix-files/src/path_buf.rs
Expand Up @@ -3,7 +3,6 @@ use std::{
str::FromStr,
};

use actix_utils::future::{ready, Ready};
use actix_web::{dev::Payload, FromRequest, HttpRequest};

use crate::error::UriSegmentError;
Expand Down Expand Up @@ -88,10 +87,10 @@ impl AsRef<Path> for PathBufWrap {

impl FromRequest for PathBufWrap {
type Error = UriSegmentError;
type Future = Ready<Result<Self, Self::Error>>;

fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
ready(req.match_info().unprocessed().parse())
#[inline]
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {
req.match_info().unprocessed().parse()
}
}

Expand Down
1 change: 1 addition & 0 deletions actix-web/Cargo.toml
Expand Up @@ -100,6 +100,7 @@ serde_json = "1.0"
serde_urlencoded = "0.7"
smallvec = "1.6.1"
socket2 = "0.5"
tokio = { version = "1.24.2", features = ["macros"] }
time = { version = "0.3", default-features = false, features = ["formatting"] }
url = "2.1"

Expand Down
8 changes: 3 additions & 5 deletions actix-web/src/data.rs
@@ -1,7 +1,6 @@
use std::{any::type_name, ops::Deref, sync::Arc};

use actix_http::Extensions;
use actix_utils::future::{err, ok, Ready};
use futures_core::future::LocalBoxFuture;
use serde::{de, Serialize};

Expand Down Expand Up @@ -159,12 +158,11 @@

impl<T: ?Sized + 'static> FromRequest for Data<T> {
type Error = Error;
type Future = Ready<Result<Self, Error>>;

#[inline]
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {

Check failure on line 163 in actix-web/src/data.rs

View workflow job for this annotation

GitHub Actions / io-uring tests

functions in traits cannot be declared `async`
if let Some(st) = req.app_data::<Data<T>>() {
ok(st.clone())
Ok(st.clone())
} else {
log::debug!(
"Failed to extract `Data<{}>` for `{}` handler. For the Data extractor to work \
Expand All @@ -174,7 +172,7 @@
req.match_name().unwrap_or_else(|| req.path())
);

err(error::ErrorInternalServerError(
Err(error::ErrorInternalServerError(
"Requested application data is not configured correctly. \
View/enable debug logs for more details.",
))
Expand Down
169 changes: 34 additions & 135 deletions actix-web/src/extract.rs
Expand Up @@ -3,13 +3,11 @@
use std::{
convert::Infallible,
future::Future,
marker::PhantomData,
pin::Pin,
task::{Context, Poll},
};

use actix_http::{Method, Uri};
use actix_utils::future::{ok, Ready};
use futures_core::ready;
use pin_project_lite::pin_project;

Expand Down Expand Up @@ -66,33 +64,17 @@
/// The associated error which can be returned.
type Error: Into<Error>;

/// Future that resolves to a `Self`.
///
/// To use an async function or block, the futures must be boxed. The following snippet will be
/// common when creating async/await extractors (that do not consume the body).
///
/// ```ignore
/// type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>;
/// // or
/// type Future = futures_util::future::LocalBoxFuture<'static, Result<Self, Self::Error>>;
///
/// fn from_request(req: HttpRequest, ...) -> Self::Future {
/// let req = req.clone();
/// Box::pin(async move {
/// ...
/// })
/// }
/// ```
type Future: Future<Output = Result<Self, Self::Error>>;

/// Create a `Self` from request parts asynchronously.
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future;
/// Creates a `Self` from request parts asynchronously.
fn from_request(
req: &HttpRequest,
payload: &mut Payload,
) -> impl Future<Output = Result<Self, Self::Error>>;

Check failure on line 71 in actix-web/src/extract.rs

View workflow job for this annotation

GitHub Actions / io-uring tests

`impl Trait` only allowed in function and inherent method return types, not in trait method return types

/// Create a `Self` from request head asynchronously.
///
/// This method is short for `T::from_request(req, &mut Payload::None)`.
fn extract(req: &HttpRequest) -> Self::Future {
Self::from_request(req, &mut Payload::None)
fn extract(req: &HttpRequest) -> impl Future<Output = Result<Self, Self::Error>> {

Check failure on line 76 in actix-web/src/extract.rs

View workflow job for this annotation

GitHub Actions / io-uring tests

`impl Trait` only allowed in function and inherent method return types, not in trait method return types
async { Self::from_request(req, &mut Payload::None).await }
}
}

Expand Down Expand Up @@ -146,12 +128,19 @@
T: FromRequest,
{
type Error = Infallible;
type Future = FromRequestOptFuture<T::Future>;

#[inline]
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
FromRequestOptFuture {
fut: T::from_request(req, payload),
async fn from_request(req: &HttpRequest, payload: &mut Payload) -> Result<Self, Self::Error> {

Check failure on line 133 in actix-web/src/extract.rs

View workflow job for this annotation

GitHub Actions / io-uring tests

functions in traits cannot be declared `async`
match T::from_request(req, payload).await {
Ok(t) => Ok(Some(t)),
Err(err) => {
log::debug!(
"Error from `Option<{}>` extractor: {}",
std::any::type_name::<T>(),
err.into()
);
Ok(None)
}
}
}
}
Expand Down Expand Up @@ -203,9 +192,11 @@
///
/// impl FromRequest for Thing {
/// type Error = Error;
/// type Future = Ready<Result<Thing, Error>>;
///
/// fn from_request(req: &HttpRequest, payload: &mut dev::Payload) -> Self::Future {
/// async fn from_request(
/// req: &HttpRequest,
/// payload: &mut dev::Payload,
/// ) -> Result<Self, Self::Error> {
/// if rand::random() {
/// ok(Thing { name: "thingy".into() })
/// } else {
Expand All @@ -232,36 +223,10 @@
T::Error: Into<E>,
{
type Error = Infallible;
type Future = FromRequestResFuture<T::Future, E>;

#[inline]
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
FromRequestResFuture {
fut: T::from_request(req, payload),
_phantom: PhantomData,
}
}
}

pin_project! {
pub struct FromRequestResFuture<Fut, E> {
#[pin]
fut: Fut,
_phantom: PhantomData<E>,
}
}

impl<Fut, T, Ei, E> Future for FromRequestResFuture<Fut, E>
where
Fut: Future<Output = Result<T, Ei>>,
Ei: Into<E>,
{
type Output = Result<Result<T, E>, Infallible>;

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let res = ready!(this.fut.poll(cx));
Poll::Ready(Ok(res.map_err(Into::into)))
async fn from_request(req: &HttpRequest, payload: &mut Payload) -> Result<Self, Self::Error> {

Check failure on line 228 in actix-web/src/extract.rs

View workflow job for this annotation

GitHub Actions / io-uring tests

functions in traits cannot be declared `async`
Ok(T::from_request(req, payload).await.map_err(Into::into))
}
}

Expand All @@ -279,10 +244,9 @@
/// ```
impl FromRequest for Uri {
type Error = Infallible;
type Future = Ready<Result<Self, Self::Error>>;

fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
ok(req.uri().clone())
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {

Check failure on line 248 in actix-web/src/extract.rs

View workflow job for this annotation

GitHub Actions / io-uring tests

functions in traits cannot be declared `async`
Ok(req.uri().clone())
}
}

Expand All @@ -300,10 +264,9 @@
/// ```
impl FromRequest for Method {
type Error = Infallible;
type Future = Ready<Result<Self, Self::Error>>;

fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
ok(req.method().clone())
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {

Check failure on line 268 in actix-web/src/extract.rs

View workflow job for this annotation

GitHub Actions / io-uring tests

functions in traits cannot be declared `async`
Ok(req.method().clone())
}
}

Expand All @@ -319,88 +282,24 @@
impl<$($T: FromRequest + 'static),+> FromRequest for ($($T,)+)
{
type Error = Error;
type Future = $fut<$($T),+>;

fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
$fut {
$(
$T: ExtractFuture::Future {
fut: $T::from_request(req, payload)
},
)+
}
}
}

pin_project! {
pub struct $fut<$($T: FromRequest),+> {
async fn from_request(req: &HttpRequest, payload: &mut Payload) -> Result<Self, Self::Error> {
$(
#[pin]
$T: ExtractFuture<$T::Future, $T>,
let $T = $T::from_request(req, payload).await.map_err(Into::into)?;
)+
}
}

impl<$($T: FromRequest),+> Future for $fut<$($T),+>
{
type Output = Result<($($T,)+), Error>;

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut this = self.project();

let mut ready = true;
$(
match this.$T.as_mut().project() {
ExtractProj::Future { fut } => match fut.poll(cx) {
Poll::Ready(Ok(output)) => {
let _ = this.$T.as_mut().project_replace(ExtractFuture::Done { output });
},
Poll::Ready(Err(err)) => return Poll::Ready(Err(err.into())),
Poll::Pending => ready = false,
},
ExtractProj::Done { .. } => {},
ExtractProj::Empty => unreachable!("FromRequest polled after finished"),
}
)+

if ready {
Poll::Ready(Ok(
($(
match this.$T.project_replace(ExtractFuture::Empty) {
ExtractReplaceProj::Done { output } => output,
_ => unreachable!("FromRequest polled after finished"),
},
)+)
))
} else {
Poll::Pending
}
Ok(($($T,)+))
}
}
};
}

pin_project! {
#[project = ExtractProj]
#[project_replace = ExtractReplaceProj]
enum ExtractFuture<Fut, Res> {
Future {
#[pin]
fut: Fut
},
Done {
output: Res,
},
Empty
}
}

impl FromRequest for () {
type Error = Infallible;
type Future = Ready<Result<Self, Self::Error>>;

fn from_request(_: &HttpRequest, _: &mut Payload) -> Self::Future {
ok(())
#[inline]
async fn from_request(_: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {

Check failure on line 301 in actix-web/src/extract.rs

View workflow job for this annotation

GitHub Actions / io-uring tests

functions in traits cannot be declared `async`
Ok(())
}
}

Expand Down
15 changes: 7 additions & 8 deletions actix-web/src/info.rs
@@ -1,6 +1,5 @@
use std::{convert::Infallible, net::SocketAddr};

use actix_utils::future::{err, ok, Ready};
use derive_more::{Display, Error};

use crate::{
Expand Down Expand Up @@ -198,10 +197,10 @@

impl FromRequest for ConnectionInfo {
type Error = Infallible;
type Future = Ready<Result<Self, Self::Error>>;

fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
ok(req.connection_info().clone())
#[inline]
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {

Check failure on line 202 in actix-web/src/info.rs

View workflow job for this annotation

GitHub Actions / io-uring tests

functions in traits cannot be declared `async`
Ok(req.connection_info().clone())
}
}

Expand Down Expand Up @@ -240,14 +239,14 @@

impl FromRequest for PeerAddr {
type Error = MissingPeerAddr;
type Future = Ready<Result<Self, Self::Error>>;

fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
#[inline]
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {

Check failure on line 244 in actix-web/src/info.rs

View workflow job for this annotation

GitHub Actions / io-uring tests

functions in traits cannot be declared `async`
match req.peer_addr() {
Some(addr) => ok(PeerAddr(addr)),
Some(addr) => Ok(PeerAddr(addr)),
None => {
log::error!("Missing peer address.");
err(MissingPeerAddr)
Err(MissingPeerAddr)
}
}
}
Expand Down
11 changes: 5 additions & 6 deletions actix-web/src/request.rs
@@ -1,13 +1,13 @@
use std::{
cell::{Ref, RefCell, RefMut},
convert::Infallible,
fmt, net,
rc::Rc,
str,
};

use actix_http::{Message, RequestHead};
use actix_router::{Path, Url};
use actix_utils::future::{ok, Ready};
#[cfg(feature = "cookies")]
use cookie::{Cookie, ParseError as CookieParseError};
use smallvec::SmallVec;
Expand All @@ -20,7 +20,7 @@ use crate::{
http::{header::HeaderMap, Method, Uri, Version},
info::ConnectionInfo,
rmap::ResourceMap,
Error, FromRequest, HttpMessage,
FromRequest, HttpMessage,
};

#[cfg(feature = "cookies")]
Expand Down Expand Up @@ -417,12 +417,11 @@ impl Drop for HttpRequest {
/// );
/// ```
impl FromRequest for HttpRequest {
type Error = Error;
type Future = Ready<Result<Self, Error>>;
type Error = Infallible;

#[inline]
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
ok(req.clone())
async fn from_request(req: &HttpRequest, _: &mut Payload) -> Result<Self, Self::Error> {
Ok(req.clone())
}
}

Expand Down