How can I do something like Arc<dyn AsyncRead + AsyncWrite>? (dyn of sum of traits)

I'm trying to store an object that implements 2 traits:

pub struct AsyncTransporter {
    stream: Arc<dyn AsyncRead + AsyncWrite>,
}

Error:

error[E0225]: only auto traits can be used as additional traits in a trait object
  --> examples/async_transporter.rs:60:33
   |
60 |     stream: Arc<dyn AsyncRead + AsyncWrite>,
   |                     ---------   ^^^^^^^^^^ additional non-auto trait
   |                     |
   |                     first non-auto trait
   |
   = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: tokio::io::AsyncRead + tokio::io::AsyncWrite {}`
   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>

I did my new trait:

trait AsyncRW: tokio::io::AsyncRead + tokio::io::AsyncWrite {}

but then I get errors saying it does not contain the methods of AsyncWrite and AsyncRead.

Is it perhaps saying that I should reimplement AsyncWrite's and AsyncRead's methods in AsyncRW? I don't see how that would be done.

How should I store an object that implements both AsyncRead and AsyncWrite?

Without the text of these error messages, it's hard to tell. Did you remember to implement your new trait for the relevant types?

impl<T> AsyncRW for T where T: tokio::io::AsyncRead + tokio::io::AsyncWrite {}
1 Like

An object like this would be pretty useless because the AsyncRead/AsyncWrite traits require mutable access in order to use them, but an Arc provides only immutable access.

Maybe you can explain what you are trying to accomplish with this? Perhaps tokio::io::split would be useful for you?

2 Likes

I didn't reach to the point of having to call poll_read on it so yes I think I should do Arc<Mutex<dyn AsyncRead + AsyncWrite>> then.

Well, hyper can be customized with a custom transporter like this: rust_hyper_custom_transporter/custom_req.rs at master · lzunsec/rust_hyper_custom_transporter · GitHub

I implemented AsyncRead and AsyncWrite for a custom socket I have. I want to use this socket into this custom transporter. it should be just a matter of doing


impl AsyncRead for CustomResponse {
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut tokio::io::ReadBuf<'_>
    ) -> Poll<std::io::Result<()>> {
       self.socket.poll_read(cx, buf)
    }

where self.socket would be my Arc<Mutex<dyn AsyncRead + AsyncWrite>>.

Indeed I could create a ReadHalf and a WriteHalf, but I already implemented both AsyncWrite and AscynRead on the same socket.