From 6d58e01217a985004c73260516730bad99b702e9 Mon Sep 17 00:00:00 2001 From: ultrabear Date: Sun, 23 Mar 2025 17:25:34 -0700 Subject: [PATCH] make Request and RequestBuilder implement IntoFuture --- crates/net/src/http/request.rs | 85 +++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 7 deletions(-) diff --git a/crates/net/src/http/request.rs b/crates/net/src/http/request.rs index 1950d856..36c29c79 100644 --- a/crates/net/src/http/request.rs +++ b/crates/net/src/http/request.rs @@ -4,7 +4,10 @@ use http::Method; use js_sys::{ArrayBuffer, Uint8Array}; use std::convert::{From, TryFrom, TryInto}; use std::fmt; +use std::future::{Future, IntoFuture}; +use std::pin::Pin; use std::str::FromStr; +use std::task::{Context, Poll}; use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}; use wasm_bindgen_futures::JsFuture; use web_sys::{ @@ -188,10 +191,10 @@ impl RequestBuilder { self.options.signal(signal); self } + /// Builds the request and send it to the server, returning the received response. pub async fn send(self) -> Result { - let req: Request = self.try_into()?; - req.send().await + self.await } /// Builds the request. pub fn build(self) -> Result { @@ -199,6 +202,51 @@ impl RequestBuilder { } } +impl IntoFuture for RequestBuilder { + type Output = Result; + + type IntoFuture = RequestBuilderFuture; + + fn into_future(self) -> Self::IntoFuture { + RequestBuilderFuture(match TryInto::::try_into(self) { + Ok(req) => RequestBuilderFutureInner::Request(req.into_future()), + Err(e) => RequestBuilderFutureInner::Immediate(Some(e)), + }) + } +} + +#[derive(Debug)] +enum RequestBuilderFutureInner { + Immediate(Option), + Request(RequestFuture), +} + +impl Future for RequestBuilderFutureInner { + type Output = Result; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match self.get_mut() { + RequestBuilderFutureInner::Immediate(ref mut e) => { + Poll::Ready(Err(e.take().expect("Polled after Ready was returned"))) + } + RequestBuilderFutureInner::Request(ref mut httpfuture) => { + Future::poll(Pin::new(httpfuture), cx) + } + } + } +} + +#[derive(Debug)] +pub struct RequestBuilderFuture(RequestBuilderFutureInner); + +impl Future for RequestBuilderFuture { + type Output = Result; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + Future::poll(Pin::new(&mut self.0), cx) + } +} + impl TryFrom for Request { type Error = crate::error::Error; @@ -330,13 +378,36 @@ impl Request { /// Executes the request. pub async fn send(self) -> Result { + self.await + } +} + +impl IntoFuture for Request { + type Output = Result; + type IntoFuture = RequestFuture; + + fn into_future(self) -> Self::IntoFuture { let request = self.0; let promise = fetch_with_request(&request); - let response = JsFuture::from(promise).await.map_err(js_to_error)?; - response - .dyn_into::() - .map_err(|e| panic!("fetch returned {:?}, not `Response` - this is a bug", e)) - .map(Response::from) + RequestFuture(JsFuture::from(promise)) + } +} + +#[derive(Debug)] +pub struct RequestFuture(JsFuture); + +impl Future for RequestFuture { + type Output = Result; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + JsFuture::poll(Pin::new(&mut self.0), cx).map(|v| { + let response = v.map_err(js_to_error)?; + + response + .dyn_into::() + .map_err(|e| panic!("fetch returned {:?}, not `Response` - this is a bug", e)) + .map(Response::from) + }) } }