Reputation: 510
I am trying to wrap a stream object with the goal of introducing some timeouts on it's read operations, and am starting with just the bare skeleton, but not even this compiles:
use futures::io::{AsyncBufRead, AsyncRead};
use std::io;
use std::io::Result;
use std::pin::Pin;
use std::task::{Context, Poll};
pub struct ImpatientStream<T> {
inner: Pin<Box<T>>,
}
impl<T> ImpatientStream<T> {
pub fn new(stream: T) -> Self {
Self {
inner: Box::pin(stream),
}
}
}
impl<T: AsyncRead + Unpin> AsyncRead for ImpatientStream<T> {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<Result<usize>> {
self.inner.as_mut().poll_read(cx, buf)
}
}
impl<T: AsyncBufRead + Unpin> AsyncBufRead for ImpatientStream<T> {
fn poll_fill_buf(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
self.inner.as_mut().poll_fill_buf(cx)
}
fn consume(mut self: Pin<&mut Self>, amt: usize) {
self.inner.as_mut().consume(amt)
}
}
fn main() -> io::Result<()> {
Ok(())
}
When I try to compile this I get:
error[E0515]: cannot return value referencing function parameter `self`
--> src/bin/echo-server-copy.rs:31:9
|
31 | self.inner.as_mut().poll_fill_buf(cx)
| ----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `self` is borrowed here
Am I doing something wrong or is this just not possible to be done like this?
Upvotes: 2
Views: 315
Reputation: 36
For anyone coming across this in the future, the trick lies in what self
actually is. It's easy to miss that self
is actually a Pin
rather than a reference to self
.
As far as I understand it, the expression self.inner
ends up returning a Pin
which itself has a reference to self
- hence the compiler message that we return a value referencing data owned by the current function.
The workaround I found here is to use Pin::get_mut
which allows us to get a &mut self
, and thus return a reference to its field self.inner
.
Updating the above example on line 31:
Pin::get_mut(self).inner.as_mut().poll_fill_buf(cx)
This can be confirmed on the playground
Also this discussion was helpful in understanding what's happening here.
Upvotes: 2