Description
Ran into quite a confusing issue in a situation like:
async fn foo<'a, St>(bar: St) -> impl Stream<...> + Send + 'a
where St: TryStream<Ok = _, Error = _> + Send + 'a
{
async_stream::stream! {
futures::pin_mut!(bar);
// eventually
bar.try_next().await;
}
}
The error I received was E0277 "St
cannot be unpinned" with a help of adding an + std::marker::Unpin
bound on the where clause. Now this lead me to question everything I thought I understood about pinning until I was answered on #tokio-users that TryStream
is not implemented for Pin<&mut T> where T: TryStream
. I guess it's not implemented because of restrictions related to the relationship of Stream
between TryStream
and nothing cannot be done for those details right now, however I was thinking this should be written into the documentation of TryStreamExt
methods and/or maybe TryStream
trait docs.
Reviewing all Unpin
bounded methods in TryStreamExt:
- try_next
- try_poll_next_unpin
- compat
- into_async_read
Of these only the into_async_read
has the following paragraph:
Note that because
into_async_read
moves the stream, theStream
type must beUnpin
. If you want to useinto_async_read
with a!Unpin
stream, you'll first have to pin the stream. This can be done by boxing the stream usingBox::pin
or pinning it to the stack using thepin_mut!
macro from thepin_utils
crate.
The above paragraph appears 1:1 on StreamExt::next
for example, and it's not too fitting for the TryStreamExt
as the real answer would be either to Box::pin
or convert to Stream
before futures::pin_mut!
. Also I am not sure if pin_utils
should be mentioned since the pin_mut!
is re-exported by futures
(or even implemented, did not check).
I think a solution would be to:
- add paragraph about using TryStreamExt methods on
!Unpin
values at the trait level docs- something about
Box::pin
'ing the value or transforming it toStream
usinginto_stream()
beforefutures::pin_mut!
- something about
- add links to trait level docs on the four methods which have
T: Unpin
bound
Any objections, ideas, could there be a better solution overall? I don't understand any/all details behind the Stream vs. TryStream and the reason to need to call into_stream()
.