0
votes

I have a struct MyAsyncStream and tokio::io::AsyncWrite implementation for it:

impl<S: AsyncRead + AsyncWrite + Unpin> AsyncWrite for MyAsyncStream<S> {
    fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<Result<usize>> {
       ....
    }

I also have MyAsyncStreamWrapper:

struct MyAsyncStreamWrapper{inner: MyAsyncStream}

Now I want to implement AnotherTrait trait for MyAsyncStreamWrapper, with the following method:

impl AnotherTrait for MyAsyncStreamWrapper {
    fn poll_send_to<B>(self: Pin<&Self>, cx: &mut Context<'_>, buf: &[u8], addr: B,) -> Poll<Result<usize, Self::Error>> {
        Pin::new(&mut self.inner).poll_write(cx, buf)
    }
    ....
}

In this method implementation, I want to call poll_write on the inner. But, unfortunately they are different on self mutability: Pin<&mut Self> vs Pin<&Self>. As expected it does not compile.

Is there an idiomatic "workaround" for such case? My idea is to wrap inner into Mutex so I could have mutable MyAsyncStream in the non-mutable context:

MyAsyncStreamWrapper{inner: Mutex<RefCell<MyAsyncStream>>}
...
fn poll_send_to<B>(mut self: Pin<&Self>, cx: &mut Context<'_>, buf: &[u8], addr: B,) -> Poll<Result<usize, Self::Error>> {
       let rc = self.stream.lock().unwrap();
       let ref mut inner  = rc.borrow();
       let pin = Pin::new(inner);

       pin.poll_write(cx, buf);
    }
...

But, unfortunately, it also does not compile, with the following error:

     pin.poll_write(cx, buf);
         ^^^^^^^^^^ method not found in `std::pin::Pin<&mut std::cell::RefMut<'_, MyAsyncStream>>`

What is the right way to go?

1

1 Answers

1
votes

Dereference then re-borrow seems to work:

use std::cell::RefCell;
use std::pin::Pin;
use std::sync::Mutex;

fn main() {
    let a = Mutex::new(RefCell::new(42));
    let rc = a.lock().unwrap();
    let mut inner = rc.borrow_mut();
    let pinned = Pin::new(&mut *inner);
    print_type_name(pinned);
}

fn print_type_name<T>(_: T) {
    println!("{}", std::any::type_name::<T>());
}

It outputs that the type is core::pin::Pin<&mut i32>.

That being said, using blocking synchronization primitives like Mutex in asynchronous context is probably not a good idea. If possible it is better to let poll_send_to take a Pin<&mut Self> parameter.