Splitting tokio's UnixStream

I'm having trouble asyncifying a certain piece of code. When doing things synchronously, I would just clone a UnixStream, and pass around one as a Reader, and the other as a Writer.

Now though I need the async variants, and tokio does have an async UnixStream, which I can split to get an AsyncReader and an AsyncWriter. Now though, those contain references, so I can't pass them into tasks to run, because they aren't 'static. How can I deal with that?

Here's the code in question:

pub async fn new_unix_socket<H, P: AsRef<Path> + Clone>(
  path: P,
  handler: H,
) -> io::Result<(Neovim<WriteHalf>, JoinHandle<Result<(), Box<LoopError>>>)>
where
  H: Handler<Writer = WriteHalf> + Send + 'static,
{
  let (reader, writer) = UnixStream::connect(path).await?.split();

  let (neovim, io) = Neovim::<WriteHalf>::new(reader, writer, handler);
  let io_handle = spawn(io);

  Ok((neovim, io_handle))
}

This does not work, of course, but I wanted to make some comments on the concrete uses here. I need to construct a Neovim, which will be sent to tasks all over the place. I contains an AsyncWriter (that's the type argument), which I' wrapping in an Arc<Mutex>> until now, so I can just clone it and send it to the tasks. The other thing is io, a future I construct and spawn, which represents an io loop. Until now, it owns the AsyncReader, and also has a clone of the Arc<Mutex<AsyncWrite>>er.

So, I kinda think I needs owned variants here to send them around to other tasks. If I were directly using threads, I'd look for scoped threads so I can send references, but I can't do so with tasks, right? One thing I could imagine is to move the AsyncReader and the AsyncWriteer into the io loop both, and the Neovim instance just gets a channel to send things through it wants written into the AsyncWrite. But that still doesn't solve the problem I have that I can't send references to the io-loop-task...

Ok, so any ideas, hints, am I missing something? The crate in question is here, but note it contains this functions in a broken state, because this just opens 2 streams, which won't work.

Thanks for any pointers :slight_smile:

You could convert it to a std UnixStream, call try_clone and convert both halves back?

1 Like

That ...er ..uhh... sounds too easy, really. Gonna give this a shot, thanks a lot!

1 Like

If someone else finds this, an alternative is to use https://docs.rs/tokio/0.2.6/tokio/io/fn.split.html, which gives back owned variants.

As an additional aside, this doesn't quite work out the same. Sometimes.

I've used @alice's idea with a TcpStream as well, and all seemed fine, until I enabled CI on windows also. I 'm not certain why it's the case, but the stream would always be closed, until I used https://docs.rs/tokio/0.2.6/tokio/io/fn.split.html instead, which works properly. No idea why it's fine on linux...

The gist is: Use tokio::io::split :slight_smile: