Replies: 2 comments 4 replies
-
Note that the same body types are used both for the request and for the response, so extra bounds that put extra burden on the request turn into extra benefits on the response. We made the body I'm not entirely sure right now how valuable it is for the response body to be |
Beta Was this translation helpful? Give feedback.
-
Isahc will not access the same //! This mod is inspired by [async-compression](https://docs.rs/crate/async-compression/0.3.1/source/src/unshared.rs)
//!
//! More discussion could be found at [What shall Sync mean across an .await?](https://internals.rust-lang.org/t/what-shall-sync-mean-across-an-await/12020/26)
use std::pin::Pin;
use std::task::{Context, Poll};
use futures::AsyncRead;
use crate::BytesRead;
pub fn unshared_reader<R: BytesRead>(r: R) -> UnsharedReader<R> {
UnsharedReader::new(r)
}
/// Wraps a type and only allows unique borrowing, the main usecase is to wrap a `!Sync` type and
/// implement `Sync` for it as this type blocks having multiple shared references to the inner
/// value.
///
/// # Safety
///
/// We must be careful when accessing `inner`, there must be no way to create a shared reference to
/// it from a shared reference to an `Unshared`, as that would allow creating shared references on
/// multiple threads.
///
/// As an example deriving or implementing `Clone` is impossible, two threads could attempt to
/// clone a shared `Unshared<T>` reference which would result in accessing the same inner value
/// concurrently.
pub struct UnsharedReader<R: BytesRead>(R);
impl<R: BytesRead> UnsharedReader<R> {
pub fn new(inner: R) -> Self {
UnsharedReader(inner)
}
pub fn get_mut(&mut self) -> &mut R {
&mut self.0
}
}
/// Safety: See comments on main docs for `UnsharedReader`
unsafe impl<R: BytesRead> Sync for UnsharedReader<R> {}
impl<R: BytesRead> AsyncRead for UnsharedReader<R> {
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<std::io::Result<usize>> {
Pin::new(self.get_mut().get_mut()).poll_read(cx, buf)
}
} So, we can expose a loosen API to end-users: // Input `r` here only requires `Send`.
let mut req = self.put_object_request(&p, AsyncBody::from_reader_sized(unshared_reader(r), args.size()))?; |
Beta Was this translation helpful? Give feedback.
-
Status: Rejected
Background
Isahc
requiresBody
andAsyncBody
to haveSync
:This makes users hard to meets the requirements.
Current Behavior
The root cause on why we need
Sync
for body is we need to store them inhttp::response::Builder
'sextension
:To make our interceptors have the ability the get the body again, we store it in
extension
via:The only interceptor that depends on this is
redirect
:Proposal
We can remove the
Sync
requirement for Body, and useMutex<Option<T>>
instead to make our bodySync
:In response builder:
In redirect interceptor:
Any ideas? cc @sagebind
Beta Was this translation helpful? Give feedback.
All reactions