safety: Use send_wrapper in WASM instead of unsafe

Resolves https://github.com/http-rs/http-client/issues/40
This commit is contained in:
K.J. Valencik 2022-06-14 17:18:16 -04:00
parent 88e93dffca
commit e62818f068
No known key found for this signature in database
GPG Key ID: 35E86CAF5A00982C
2 changed files with 10 additions and 25 deletions

View File

@ -68,6 +68,7 @@ js-sys = { version = "0.3.25", optional = true }
wasm-bindgen = { version = "0.2.48", optional = true }
wasm-bindgen-futures = { version = "0.4.5", optional = true }
futures = { version = "0.3.1", optional = true }
send_wrapper = { version = "0.6.0", features = ["futures"] }
[target.'cfg(target_arch = "wasm32")'.dependencies.web-sys]
version = "0.3.25"

View File

@ -2,9 +2,9 @@
use std::convert::{Infallible, TryFrom};
use std::pin::Pin;
use std::task::{Context, Poll};
use futures::prelude::*;
use send_wrapper::SendWrapper;
use crate::Config;
@ -42,7 +42,7 @@ impl HttpClient for WasmClient {
{
let config = self.config.clone();
InnerFuture::new(async move {
wrap_send(async move {
let req: fetch::Request = fetch::Request::new(req).await?;
let conn = req.send();
let mut res = if let Some(timeout) = config.timeout {
@ -87,29 +87,13 @@ impl TryFrom<Config> for WasmClient {
}
}
struct InnerFuture {
fut: Pin<Box<dyn Future<Output = Result<Response, Error>> + 'static>>,
}
impl InnerFuture {
fn new<F: Future<Output = Result<Response, Error>> + 'static>(fut: F) -> Pin<Box<Self>> {
Box::pin(Self { fut: Box::pin(fut) })
}
}
// This is safe because WASM doesn't have threads yet. Once WASM supports threads we should use a
// thread to park the blocking implementation until it's been completed.
unsafe impl Send for InnerFuture {}
impl Future for InnerFuture {
type Output = Result<Response, Error>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// This is safe because we're only using this future as a pass-through for the inner
// future, in order to implement `Send`. If it's safe to poll the inner future, it's safe
// to proxy it too.
unsafe { Pin::new_unchecked(&mut self.fut).poll(cx) }
}
// This should not panic because WASM doesn't have threads yet. Once WASM supports threads
// we can use a thread to park the blocking implementation until it's been completed.
fn wrap_send<Fut, O>(f: Fut) -> Pin<Box<dyn Future<Output = O> + Send + Sync + 'static>>
where
Fut: Future<Output = O> + 'static,
{
Box::pin(SendWrapper::new(f))
}
mod fetch {