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?
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.